From patchwork Sun Jun 11 06:09:54 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Mani, Rajmohan" X-Patchwork-Id: 774302 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3wlm6s4d3bz9s78 for ; Sun, 11 Jun 2017 16:18:13 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751710AbdFKGRs (ORCPT ); Sun, 11 Jun 2017 02:17:48 -0400 Received: from mga04.intel.com ([192.55.52.120]:14114 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751917AbdFKGRH (ORCPT ); Sun, 11 Jun 2017 02:17:07 -0400 Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 10 Jun 2017 23:17:06 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.39,327,1493708400"; d="scan'208";a="1140060540" Received: from glacier.sc.intel.com ([10.3.62.78]) by orsmga001.jf.intel.com with ESMTP; 10 Jun 2017 23:17:06 -0700 From: Rajmohan Mani To: linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-acpi@vger.kernel.org Cc: Lee Jones , Linus Walleij , Alexandre Courbot , "Rafael J. Wysocki" , Len Brown , Rajmohan Mani Subject: [PATCH v2 2/3] gpio: Add support for TPS68470 GPIOs Date: Sat, 10 Jun 2017 23:09:54 -0700 Message-Id: <1497161395-36504-3-git-send-email-rajmohan.mani@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1497161395-36504-1-git-send-email-rajmohan.mani@intel.com> References: <1497161395-36504-1-git-send-email-rajmohan.mani@intel.com> Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org This patch adds support for TPS68470 GPIOs. There are 7 GPIOs and a few sensor related GPIOs. These GPIOs can be requested and configured as appropriate. Signed-off-by: Rajmohan Mani --- drivers/gpio/Kconfig | 14 ++++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-tps68470.c | 186 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 drivers/gpio/gpio-tps68470.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 23ca51e..9ba647e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1041,6 +1041,20 @@ config GPIO_TPS65912 help This driver supports TPS65912 gpio chip +config GPIO_TPS68470 + bool "TPS68470 GPIO" + depends on MFD_TPS68470 + help + Select this option to enable GPIO driver for the TPS68470 + chip family. + There are 7 GPIOs and few sensor related GPIOs supported + by the TPS68470. While the 7 GPIOs can be configured as + input or output as appropriate, the sensor related GPIOs + are "output only" GPIOs. + + This driver config is bool, as the GPIO functionality + of the TPS68470 must be available before dependent + drivers are loaded. config GPIO_TWL4030 tristate "TWL4030, TWL5030, and TPS659x0 GPIOs" depends on TWL4030_CORE diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 68b9627..a2659cb 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -120,6 +120,7 @@ obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o +obj-$(CONFIG_GPIO_TPS68470) += gpio-tps68470.o obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o diff --git a/drivers/gpio/gpio-tps68470.c b/drivers/gpio/gpio-tps68470.c new file mode 100644 index 0000000..548eea9 --- /dev/null +++ b/drivers/gpio/gpio-tps68470.c @@ -0,0 +1,186 @@ +/* + * GPIO driver for TPS68470 PMIC + * + * Copyright (C) 2017 Intel Corporation + * Authors: + * Antti Laakso + * Tianshu Qiu + * Jian Xu Zheng + * Yuning Pu + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#define TPS68470_N_LOGIC_OUTPUT 3 +#define TPS68470_N_REGULAR_GPIO 7 +#define TPS68470_N_GPIO (TPS68470_N_LOGIC_OUTPUT + TPS68470_N_REGULAR_GPIO) + +struct tps68470_gpio_data { + struct regmap *tps68470_regmap; + struct gpio_chip gc; +}; + +static inline struct tps68470_gpio_data *to_gpio_data(struct gpio_chip *gpiochp) +{ + return container_of(gpiochp, struct tps68470_gpio_data, gc); +} + +static int tps68470_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct tps68470_gpio_data *tps68470_gpio = to_gpio_data(gc); + struct regmap *regmap = tps68470_gpio->tps68470_regmap; + unsigned int reg = TPS68470_REG_GPDO; + int val, ret; + + if (offset >= TPS68470_N_REGULAR_GPIO) { + offset -= TPS68470_N_REGULAR_GPIO; + reg = TPS68470_REG_SGPO; + } + + ret = regmap_read(regmap, reg, &val); + if (ret) { + dev_err(tps68470_gpio->gc.parent, "reg 0x%x read failed\n", + TPS68470_REG_SGPO); + return ret; + } + return !!(val & BIT(offset)); +} + +/* Return 0 if output, 1 if input */ +static int tps68470_gpio_get_direction(struct gpio_chip *gc, + unsigned int offset) +{ + struct tps68470_gpio_data *tps68470_gpio = to_gpio_data(gc); + struct regmap *regmap = tps68470_gpio->tps68470_regmap; + int val, ret; + + /* rest are always outputs */ + if (offset >= TPS68470_N_REGULAR_GPIO) + return 0; + + ret = regmap_read(regmap, TPS68470_GPIO_CTL_REG_A(offset), &val); + if (ret) { + dev_err(tps68470_gpio->gc.parent, "reg 0x%x read failed\n", + TPS68470_GPIO_CTL_REG_A(offset)); + return ret; + } + + val &= TPS68470_GPIO_MODE_MASK; + return val >= TPS68470_GPIO_MODE_OUT_CMOS ? 0 : 1; +} + +static void tps68470_gpio_set(struct gpio_chip *gc, unsigned int offset, + int value) +{ + struct tps68470_gpio_data *tps68470_gpio = to_gpio_data(gc); + struct regmap *regmap = tps68470_gpio->tps68470_regmap; + unsigned int reg = TPS68470_REG_GPDO; + + if (offset >= TPS68470_N_REGULAR_GPIO) { + reg = TPS68470_REG_SGPO; + offset -= TPS68470_N_REGULAR_GPIO; + } + + regmap_update_bits(regmap, reg, BIT(offset), value ? BIT(offset) : 0); +} + +static int tps68470_gpio_output(struct gpio_chip *gc, unsigned int offset, + int value) +{ + struct tps68470_gpio_data *tps68470_gpio = to_gpio_data(gc); + struct regmap *regmap = tps68470_gpio->tps68470_regmap; + + /* rest are always outputs */ + if (offset >= TPS68470_N_REGULAR_GPIO) + return 0; + + /* Set the initial value */ + tps68470_gpio_set(gc, offset, value); + + return regmap_update_bits(regmap, TPS68470_GPIO_CTL_REG_A(offset), + TPS68470_GPIO_MODE_MASK, + TPS68470_GPIO_MODE_OUT_CMOS); +} + +static int tps68470_gpio_input(struct gpio_chip *gc, unsigned int offset) +{ + struct tps68470_gpio_data *tps68470_gpio = to_gpio_data(gc); + struct regmap *regmap = tps68470_gpio->tps68470_regmap; + + /* rest are always outputs */ + if (offset >= TPS68470_N_REGULAR_GPIO) + return -EINVAL; + + return regmap_update_bits(regmap, TPS68470_GPIO_CTL_REG_A(offset), + TPS68470_GPIO_MODE_MASK, 0x00); +} + +static const char *tps68470_names[TPS68470_N_GPIO] = { + "gpio.0", "gpio.1", "gpio.2", "gpio.3", + "gpio.4", "gpio.5", "gpio.6", + "s_enable", "s_idle", "s_resetn", +}; + +static int tps68470_gpio_probe(struct platform_device *pdev) +{ + struct tps68470_gpio_data *tps68470_gpio; + int i, ret; + + tps68470_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps68470_gpio), + GFP_KERNEL); + if (!tps68470_gpio) + return -ENOMEM; + + tps68470_gpio->tps68470_regmap = dev_get_drvdata(pdev->dev.parent); + tps68470_gpio->gc.label = "tps68470-gpio"; + tps68470_gpio->gc.owner = THIS_MODULE; + tps68470_gpio->gc.direction_input = tps68470_gpio_input; + tps68470_gpio->gc.direction_output = tps68470_gpio_output; + tps68470_gpio->gc.get = tps68470_gpio_get; + tps68470_gpio->gc.get_direction = tps68470_gpio_get_direction; + tps68470_gpio->gc.set = tps68470_gpio_set; + tps68470_gpio->gc.can_sleep = true; + tps68470_gpio->gc.names = tps68470_names; + tps68470_gpio->gc.ngpio = TPS68470_N_GPIO; + tps68470_gpio->gc.base = -1; + tps68470_gpio->gc.parent = &pdev->dev; + + ret = devm_gpiochip_add_data(&pdev->dev, &tps68470_gpio->gc, NULL); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register gpio_chip: %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, tps68470_gpio); + + /* + * Initialize all the GPIOs to 0, just to make sure all + * GPIOs start with known default values. This protects against + * any GPIOs getting set with a value of 1, after TPS68470 reset + */ + for (i = 0; i < tps68470_gpio->gc.ngpio; i++) + tps68470_gpio_set(&tps68470_gpio->gc, i, 0); + + return ret; +} + +static struct platform_driver tps68470_gpio_driver = { + .driver = { + .name = "tps68470-gpio", + }, + .probe = tps68470_gpio_probe, +}; + +builtin_platform_driver(tps68470_gpio_driver)