From patchwork Fri Jul 4 09:55:07 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Javier Martinez Canillas X-Patchwork-Id: 4479741 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 8027E9F26C for ; Fri, 4 Jul 2014 09:59:29 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 90F452041B for ; Fri, 4 Jul 2014 09:59:28 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 95B732025B for ; Fri, 4 Jul 2014 09:59:27 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1X30FE-0005EW-8f; Fri, 04 Jul 2014 09:57:28 +0000 Received: from bhuna.collabora.co.uk ([93.93.135.160]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1X30E4-00048E-7I for linux-arm-kernel@lists.infradead.org; Fri, 04 Jul 2014 09:56:18 +0000 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: javier) with ESMTPSA id 3330F602750 From: Javier Martinez Canillas To: Lee Jones Subject: [PATCH v6 08/23] mfd: max77686: Add Dynamic Voltage Scaling (DVS) support Date: Fri, 4 Jul 2014 11:55:07 +0200 Message-Id: <1404467722-26687-9-git-send-email-javier.martinez@collabora.co.uk> X-Mailer: git-send-email 2.0.0.rc2 In-Reply-To: <1404467722-26687-1-git-send-email-javier.martinez@collabora.co.uk> References: <1404467722-26687-1-git-send-email-javier.martinez@collabora.co.uk> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140704_025616_569244_6C3392EB X-CRM114-Status: GOOD ( 24.45 ) X-Spam-Score: -0.0 (/) Cc: Alessandro Zummo , Krzysztof Kozlowski , Kukjin Kim , Mike Turquette , Tomeu Vizoso , devicetree@vger.kernel.org, Yadwinder Singh Brar , linux-kernel@vger.kernel.org, Liam Girdwood , Javier Martinez Canillas , Doug Anderson , Tushar Behera , Mark Brown , linux-samsung-soc@vger.kernel.org, Olof Johansson , Andreas Farber , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Some regulators on the MAX77686 PMIC have Dynamic Voltage Scaling (DVS) support that allows output voltage to change dynamically. For MAX77686, these regulators are Buck regulators 2, 3 and 4. Each Buck output voltage is selected using a set of external inputs: DVS1-3 and SELB2-4. DVS registers can be used to configure the output voltages for each Buck regulator and which one is active is controled by DVSx lines. SELBx lines are used to control if individual Buck lines are ON or OFF. This patch adds support to configure the DVSx and SELBx lines from DT and to setup and read the GPIO lines connected to them. Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski --- drivers/mfd/max77686.c | 115 +++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/max77686.h | 18 ++++--- 2 files changed, 125 insertions(+), 8 deletions(-) diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index 8650832..648d564 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -32,8 +32,10 @@ #include #include #include +#include #include #include +#include #define I2C_ADDR_RTC (0x0C >> 1) @@ -101,9 +103,115 @@ static const struct of_device_id max77686_pmic_dt_match[] = { {}, }; +static void max77686_dt_parse_dvs_gpio(struct device *dev) +{ + struct max77686_platform_data *pd = dev_get_platdata(dev); + int i; + + /* + * NOTE: we don't consider GPIO errors fatal; board may have some lines + * directly pulled high or low and thus doesn't specify them. + */ + for (i = 0; i < ARRAY_SIZE(pd->buck_gpio_dvs); i++) + pd->buck_gpio_dvs[i] = + devm_gpiod_get_index(dev, "max77686,pmic-buck-dvs", i); + + for (i = 0; i < ARRAY_SIZE(pd->buck_gpio_selb); i++) + pd->buck_gpio_selb[i] = + devm_gpiod_get_index(dev, "max77686,pmic-buck-selb", i); +} + +/** + * max77686_setup_gpios - init DVS-related GPIOs + * + * This function claims / initalizations GPIOs related to DVS if they are + * defined. This may have the effect of switching voltages if the + * pdata->buck_default_idx does not match the boot time state of pins. + */ +int max77686_setup_gpios(struct device *dev) +{ + struct max77686_platform_data *pd = dev_get_platdata(dev); + int buck_default_idx = pd->buck_default_idx; + int ret; + int i; + + /* Set all SELB high to avoid glitching while DVS is changing */ + for (i = 0; i < ARRAY_SIZE(pd->buck_gpio_selb); i++) { + struct gpio_desc *gpio = pd->buck_gpio_selb[i]; + + /* OK if some GPIOs aren't defined */ + if (IS_ERR(gpio)) + continue; + + ret = gpiod_direction_output_raw(gpio, 1); + if (ret) { + dev_err(dev, "can't set gpio[%d] dir: %d\n", i, ret); + return ret; + } + } + + /* Set our initial setting */ + for (i = 0; i < ARRAY_SIZE(pd->buck_gpio_dvs); i++) { + struct gpio_desc *gpio = pd->buck_gpio_dvs[i]; + + /* OK if some GPIOs aren't defined */ + if (IS_ERR(gpio)) + continue; + + /* If a GPIO is valid, set it */ + gpiod_direction_output(gpio, (buck_default_idx >> i) & 1); + if (ret) { + dev_err(dev, "can't set gpio[%d]: dir %d\n", i, ret); + return ret; + } + } + + /* Now set SELB low to take effect */ + for (i = 0; i < ARRAY_SIZE(pd->buck_gpio_selb); i++) { + struct gpio_desc *gpio = pd->buck_gpio_selb[i]; + + if (!IS_ERR(gpio)) + gpiod_set_value(gpio, 0); + } + + return 0; +} +EXPORT_SYMBOL_GPL(max77686_setup_gpios); + +/** + * max77686_read_gpios - read the current state of the dvs GPIOs + * + * We call this function at bootup to detect what slot the firmware was + * using for the DVS GPIOs. That way we can properly preserve the firmware's + * voltage settings + */ +int max77686_read_gpios(struct max77686_platform_data *pdata) +{ + int buck_default_idx = pdata->buck_default_idx; + int result = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(pdata->buck_gpio_dvs); i++) { + struct gpio_desc *gpio = pdata->buck_gpio_dvs[i]; + + /* OK if some GPIOs aren't defined; we'll use default */ + if (IS_ERR(gpio)) { + result |= buck_default_idx & (1 << i); + continue; + } + + if (gpiod_get_value_cansleep(gpio)) + result |= 1 << i; + } + + return result; +} +EXPORT_SYMBOL_GPL(max77686_read_gpios); + static struct max77686_platform_data *max77686_i2c_parse_dt_pdata(struct device *dev) { + struct device_node *np = dev->of_node; struct max77686_platform_data *pd; pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); @@ -111,6 +219,13 @@ static struct max77686_platform_data *max77686_i2c_parse_dt_pdata(struct device return NULL; dev->platform_data = pd; + + /* Read default index and ignore errors, since default is 0 */ + of_property_read_u32(np, "max77686,pmic-buck-default-dvs-idx", + &pd->buck_default_idx); + + max77686_dt_parse_dvs_gpio(dev); + return pd; } diff --git a/include/linux/mfd/max77686.h b/include/linux/mfd/max77686.h index 4cbcc13..46a736b 100644 --- a/include/linux/mfd/max77686.h +++ b/include/linux/mfd/max77686.h @@ -99,15 +99,17 @@ struct max77686_platform_data { struct max77686_opmode_data *opmode_data; /* - * GPIO-DVS feature is not enabled with the current version of - * MAX77686 driver. Buck2/3/4_voltages[0] is used as the default - * voltage at probe. DVS/SELB gpios are set as OUTPUT-LOW. + * GPIO-DVS feature is not fully enabled with the current version of + * MAX77686 driver, but the driver does support using a DVS index other + * than the default of 0. */ - int buck234_gpio_dvs[3]; /* GPIO of [0]DVS1, [1]DVS2, [2]DVS3 */ - int buck234_gpio_selb[3]; /* [0]SELB2, [1]SELB3, [2]SELB4 */ - unsigned int buck2_voltage[8]; /* buckx_voltage in uV */ - unsigned int buck3_voltage[8]; - unsigned int buck4_voltage[8]; + struct gpio_desc *buck_gpio_dvs[3]; /* GPIO of [0]DVS1, [1]DVS2, [2]DVS3 */ + int buck_default_idx; /* Default value of DVS1, 2, 3 */ + + struct gpio_desc *buck_gpio_selb[3]; /* Buck regulators 2, 3, 4 */ }; +extern int max77686_setup_gpios(struct device *dev); +extern int max77686_read_gpios(struct max77686_platform_data *pdata); + #endif /* __LINUX_MFD_MAX77686_H */