156cc3af4SMarco Felsch // SPDX-License-Identifier: GPL-2.0 256cc3af4SMarco Felsch /* 356cc3af4SMarco Felsch * Dialog DA9062 pinctrl and GPIO driver. 456cc3af4SMarco Felsch * Based on DA9055 GPIO driver. 556cc3af4SMarco Felsch * 656cc3af4SMarco Felsch * TODO: 756cc3af4SMarco Felsch * - add pinmux and pinctrl support (gpio alternate mode) 856cc3af4SMarco Felsch * 956cc3af4SMarco Felsch * Documents: 1056cc3af4SMarco Felsch * [1] https://www.dialog-semiconductor.com/sites/default/files/da9062_datasheet_3v6.pdf 1156cc3af4SMarco Felsch * 1256cc3af4SMarco Felsch * Copyright (C) 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de> 1356cc3af4SMarco Felsch */ 1456cc3af4SMarco Felsch #include <linux/bits.h> 1556cc3af4SMarco Felsch #include <linux/module.h> 1656cc3af4SMarco Felsch #include <linux/platform_device.h> 1756cc3af4SMarco Felsch #include <linux/regmap.h> 1856cc3af4SMarco Felsch 1956cc3af4SMarco Felsch #include <linux/gpio/driver.h> 2056cc3af4SMarco Felsch 2156cc3af4SMarco Felsch #include <linux/mfd/da9062/core.h> 2256cc3af4SMarco Felsch #include <linux/mfd/da9062/registers.h> 2356cc3af4SMarco Felsch 2456cc3af4SMarco Felsch /* 2556cc3af4SMarco Felsch * We need this get the gpio_desc from a <gpio_chip,offset> tuple to decide if 2656cc3af4SMarco Felsch * the gpio is active low without a vendor specific dt-binding. 2756cc3af4SMarco Felsch */ 282353810dSYueHaibing #include "../gpio/gpiolib.h" 2956cc3af4SMarco Felsch 3056cc3af4SMarco Felsch #define DA9062_TYPE(offset) (4 * (offset % 2)) 3156cc3af4SMarco Felsch #define DA9062_PIN_SHIFT(offset) (4 * (offset % 2)) 3256cc3af4SMarco Felsch #define DA9062_PIN_ALTERNATE 0x00 /* gpio alternate mode */ 3356cc3af4SMarco Felsch #define DA9062_PIN_GPI 0x01 /* gpio in */ 3456cc3af4SMarco Felsch #define DA9062_PIN_GPO_OD 0x02 /* gpio out open-drain */ 3556cc3af4SMarco Felsch #define DA9062_PIN_GPO_PP 0x03 /* gpio out push-pull */ 3656cc3af4SMarco Felsch #define DA9062_GPIO_NUM 5 3756cc3af4SMarco Felsch 3856cc3af4SMarco Felsch struct da9062_pctl { 3956cc3af4SMarco Felsch struct da9062 *da9062; 4056cc3af4SMarco Felsch struct gpio_chip gc; 4156cc3af4SMarco Felsch unsigned int pin_config[DA9062_GPIO_NUM]; 4256cc3af4SMarco Felsch }; 4356cc3af4SMarco Felsch 4456cc3af4SMarco Felsch static int da9062_pctl_get_pin_mode(struct da9062_pctl *pctl, 4556cc3af4SMarco Felsch unsigned int offset) 4656cc3af4SMarco Felsch { 4756cc3af4SMarco Felsch struct regmap *regmap = pctl->da9062->regmap; 4856cc3af4SMarco Felsch int ret, val; 4956cc3af4SMarco Felsch 5056cc3af4SMarco Felsch ret = regmap_read(regmap, DA9062AA_GPIO_0_1 + (offset >> 1), &val); 5156cc3af4SMarco Felsch if (ret < 0) 5256cc3af4SMarco Felsch return ret; 5356cc3af4SMarco Felsch 5456cc3af4SMarco Felsch val >>= DA9062_PIN_SHIFT(offset); 5556cc3af4SMarco Felsch val &= DA9062AA_GPIO0_PIN_MASK; 5656cc3af4SMarco Felsch 5756cc3af4SMarco Felsch return val; 5856cc3af4SMarco Felsch } 5956cc3af4SMarco Felsch 6056cc3af4SMarco Felsch static int da9062_pctl_set_pin_mode(struct da9062_pctl *pctl, 6156cc3af4SMarco Felsch unsigned int offset, unsigned int mode_req) 6256cc3af4SMarco Felsch { 6356cc3af4SMarco Felsch struct regmap *regmap = pctl->da9062->regmap; 6456cc3af4SMarco Felsch unsigned int mode = mode_req; 6556cc3af4SMarco Felsch unsigned int mask; 6656cc3af4SMarco Felsch int ret; 6756cc3af4SMarco Felsch 6856cc3af4SMarco Felsch mode &= DA9062AA_GPIO0_PIN_MASK; 6956cc3af4SMarco Felsch mode <<= DA9062_PIN_SHIFT(offset); 7056cc3af4SMarco Felsch mask = DA9062AA_GPIO0_PIN_MASK << DA9062_PIN_SHIFT(offset); 7156cc3af4SMarco Felsch 7256cc3af4SMarco Felsch ret = regmap_update_bits(regmap, DA9062AA_GPIO_0_1 + (offset >> 1), 7356cc3af4SMarco Felsch mask, mode); 7456cc3af4SMarco Felsch if (!ret) 7556cc3af4SMarco Felsch pctl->pin_config[offset] = mode_req; 7656cc3af4SMarco Felsch 7756cc3af4SMarco Felsch return ret; 7856cc3af4SMarco Felsch } 7956cc3af4SMarco Felsch 8056cc3af4SMarco Felsch static int da9062_gpio_get(struct gpio_chip *gc, unsigned int offset) 8156cc3af4SMarco Felsch { 8256cc3af4SMarco Felsch struct da9062_pctl *pctl = gpiochip_get_data(gc); 8356cc3af4SMarco Felsch struct regmap *regmap = pctl->da9062->regmap; 8456cc3af4SMarco Felsch int gpio_mode, val; 8556cc3af4SMarco Felsch int ret; 8656cc3af4SMarco Felsch 8756cc3af4SMarco Felsch gpio_mode = da9062_pctl_get_pin_mode(pctl, offset); 8856cc3af4SMarco Felsch if (gpio_mode < 0) 8956cc3af4SMarco Felsch return gpio_mode; 9056cc3af4SMarco Felsch 9156cc3af4SMarco Felsch switch (gpio_mode) { 9256cc3af4SMarco Felsch case DA9062_PIN_ALTERNATE: 9356cc3af4SMarco Felsch return -ENOTSUPP; 9456cc3af4SMarco Felsch case DA9062_PIN_GPI: 9556cc3af4SMarco Felsch ret = regmap_read(regmap, DA9062AA_STATUS_B, &val); 9656cc3af4SMarco Felsch if (ret < 0) 9756cc3af4SMarco Felsch return ret; 9856cc3af4SMarco Felsch break; 9956cc3af4SMarco Felsch case DA9062_PIN_GPO_OD: 10056cc3af4SMarco Felsch case DA9062_PIN_GPO_PP: 10156cc3af4SMarco Felsch ret = regmap_read(regmap, DA9062AA_GPIO_MODE0_4, &val); 10256cc3af4SMarco Felsch if (ret < 0) 10356cc3af4SMarco Felsch return ret; 10456cc3af4SMarco Felsch } 10556cc3af4SMarco Felsch 10656cc3af4SMarco Felsch return !!(val & BIT(offset)); 10756cc3af4SMarco Felsch } 10856cc3af4SMarco Felsch 10956cc3af4SMarco Felsch static void da9062_gpio_set(struct gpio_chip *gc, unsigned int offset, 11056cc3af4SMarco Felsch int value) 11156cc3af4SMarco Felsch { 11256cc3af4SMarco Felsch struct da9062_pctl *pctl = gpiochip_get_data(gc); 11356cc3af4SMarco Felsch struct regmap *regmap = pctl->da9062->regmap; 11456cc3af4SMarco Felsch 11556cc3af4SMarco Felsch regmap_update_bits(regmap, DA9062AA_GPIO_MODE0_4, BIT(offset), 11656cc3af4SMarco Felsch value << offset); 11756cc3af4SMarco Felsch } 11856cc3af4SMarco Felsch 11956cc3af4SMarco Felsch static int da9062_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) 12056cc3af4SMarco Felsch { 12156cc3af4SMarco Felsch struct da9062_pctl *pctl = gpiochip_get_data(gc); 12256cc3af4SMarco Felsch int gpio_mode; 12356cc3af4SMarco Felsch 12456cc3af4SMarco Felsch gpio_mode = da9062_pctl_get_pin_mode(pctl, offset); 12556cc3af4SMarco Felsch if (gpio_mode < 0) 12656cc3af4SMarco Felsch return gpio_mode; 12756cc3af4SMarco Felsch 12856cc3af4SMarco Felsch switch (gpio_mode) { 12956cc3af4SMarco Felsch case DA9062_PIN_ALTERNATE: 13056cc3af4SMarco Felsch return -ENOTSUPP; 13156cc3af4SMarco Felsch case DA9062_PIN_GPI: 13256cc3af4SMarco Felsch return GPIO_LINE_DIRECTION_IN; 13356cc3af4SMarco Felsch case DA9062_PIN_GPO_OD: 13456cc3af4SMarco Felsch case DA9062_PIN_GPO_PP: 13556cc3af4SMarco Felsch return GPIO_LINE_DIRECTION_OUT; 13656cc3af4SMarco Felsch } 13756cc3af4SMarco Felsch 13856cc3af4SMarco Felsch return -EINVAL; 13956cc3af4SMarco Felsch } 14056cc3af4SMarco Felsch 14156cc3af4SMarco Felsch static int da9062_gpio_direction_input(struct gpio_chip *gc, 14256cc3af4SMarco Felsch unsigned int offset) 14356cc3af4SMarco Felsch { 14456cc3af4SMarco Felsch struct da9062_pctl *pctl = gpiochip_get_data(gc); 14556cc3af4SMarco Felsch struct regmap *regmap = pctl->da9062->regmap; 14656cc3af4SMarco Felsch struct gpio_desc *desc = gpiochip_get_desc(gc, offset); 14756cc3af4SMarco Felsch unsigned int gpi_type; 14856cc3af4SMarco Felsch int ret; 14956cc3af4SMarco Felsch 15056cc3af4SMarco Felsch ret = da9062_pctl_set_pin_mode(pctl, offset, DA9062_PIN_GPI); 15156cc3af4SMarco Felsch if (ret) 15256cc3af4SMarco Felsch return ret; 15356cc3af4SMarco Felsch 15456cc3af4SMarco Felsch /* 15556cc3af4SMarco Felsch * If the gpio is active low we should set it in hw too. No worries 15656cc3af4SMarco Felsch * about gpio_get() because we read and return the gpio-level. So the 15756cc3af4SMarco Felsch * gpiolib active_low handling is still correct. 15856cc3af4SMarco Felsch * 15956cc3af4SMarco Felsch * 0 - active low, 1 - active high 16056cc3af4SMarco Felsch */ 16156cc3af4SMarco Felsch gpi_type = !gpiod_is_active_low(desc); 16256cc3af4SMarco Felsch 16356cc3af4SMarco Felsch return regmap_update_bits(regmap, DA9062AA_GPIO_0_1 + (offset >> 1), 16456cc3af4SMarco Felsch DA9062AA_GPIO0_TYPE_MASK << DA9062_TYPE(offset), 16556cc3af4SMarco Felsch gpi_type << DA9062_TYPE(offset)); 16656cc3af4SMarco Felsch } 16756cc3af4SMarco Felsch 16856cc3af4SMarco Felsch static int da9062_gpio_direction_output(struct gpio_chip *gc, 16956cc3af4SMarco Felsch unsigned int offset, int value) 17056cc3af4SMarco Felsch { 17156cc3af4SMarco Felsch struct da9062_pctl *pctl = gpiochip_get_data(gc); 17256cc3af4SMarco Felsch unsigned int pin_config = pctl->pin_config[offset]; 17356cc3af4SMarco Felsch int ret; 17456cc3af4SMarco Felsch 17556cc3af4SMarco Felsch ret = da9062_pctl_set_pin_mode(pctl, offset, pin_config); 17656cc3af4SMarco Felsch if (ret) 17756cc3af4SMarco Felsch return ret; 17856cc3af4SMarco Felsch 17956cc3af4SMarco Felsch da9062_gpio_set(gc, offset, value); 18056cc3af4SMarco Felsch 18156cc3af4SMarco Felsch return 0; 18256cc3af4SMarco Felsch } 18356cc3af4SMarco Felsch 18456cc3af4SMarco Felsch static int da9062_gpio_set_config(struct gpio_chip *gc, unsigned int offset, 18556cc3af4SMarco Felsch unsigned long config) 18656cc3af4SMarco Felsch { 18756cc3af4SMarco Felsch struct da9062_pctl *pctl = gpiochip_get_data(gc); 18856cc3af4SMarco Felsch struct regmap *regmap = pctl->da9062->regmap; 18956cc3af4SMarco Felsch int gpio_mode; 19056cc3af4SMarco Felsch 19156cc3af4SMarco Felsch /* 19256cc3af4SMarco Felsch * We need to meet the following restrictions [1, Figure 18]: 19356cc3af4SMarco Felsch * - PIN_CONFIG_BIAS_PULL_DOWN -> only allowed if the pin is used as 19456cc3af4SMarco Felsch * gpio input 19556cc3af4SMarco Felsch * - PIN_CONFIG_BIAS_PULL_UP -> only allowed if the pin is used as 19656cc3af4SMarco Felsch * gpio output open-drain. 19756cc3af4SMarco Felsch */ 19856cc3af4SMarco Felsch 19956cc3af4SMarco Felsch switch (pinconf_to_config_param(config)) { 20056cc3af4SMarco Felsch case PIN_CONFIG_BIAS_DISABLE: 20156cc3af4SMarco Felsch return regmap_update_bits(regmap, DA9062AA_CONFIG_K, 20256cc3af4SMarco Felsch BIT(offset), 0); 20356cc3af4SMarco Felsch case PIN_CONFIG_BIAS_PULL_DOWN: 20456cc3af4SMarco Felsch gpio_mode = da9062_pctl_get_pin_mode(pctl, offset); 20556cc3af4SMarco Felsch if (gpio_mode < 0) 20656cc3af4SMarco Felsch return -EINVAL; 20756cc3af4SMarco Felsch else if (gpio_mode != DA9062_PIN_GPI) 20856cc3af4SMarco Felsch return -ENOTSUPP; 20956cc3af4SMarco Felsch return regmap_update_bits(regmap, DA9062AA_CONFIG_K, 21056cc3af4SMarco Felsch BIT(offset), BIT(offset)); 21156cc3af4SMarco Felsch case PIN_CONFIG_BIAS_PULL_UP: 21256cc3af4SMarco Felsch gpio_mode = da9062_pctl_get_pin_mode(pctl, offset); 21356cc3af4SMarco Felsch if (gpio_mode < 0) 21456cc3af4SMarco Felsch return -EINVAL; 21556cc3af4SMarco Felsch else if (gpio_mode != DA9062_PIN_GPO_OD) 21656cc3af4SMarco Felsch return -ENOTSUPP; 21756cc3af4SMarco Felsch return regmap_update_bits(regmap, DA9062AA_CONFIG_K, 21856cc3af4SMarco Felsch BIT(offset), BIT(offset)); 21956cc3af4SMarco Felsch case PIN_CONFIG_DRIVE_OPEN_DRAIN: 22056cc3af4SMarco Felsch return da9062_pctl_set_pin_mode(pctl, offset, 22156cc3af4SMarco Felsch DA9062_PIN_GPO_OD); 22256cc3af4SMarco Felsch case PIN_CONFIG_DRIVE_PUSH_PULL: 22356cc3af4SMarco Felsch return da9062_pctl_set_pin_mode(pctl, offset, 22456cc3af4SMarco Felsch DA9062_PIN_GPO_PP); 22556cc3af4SMarco Felsch default: 22656cc3af4SMarco Felsch return -ENOTSUPP; 22756cc3af4SMarco Felsch } 22856cc3af4SMarco Felsch } 22956cc3af4SMarco Felsch 23056cc3af4SMarco Felsch static int da9062_gpio_to_irq(struct gpio_chip *gc, unsigned int offset) 23156cc3af4SMarco Felsch { 23256cc3af4SMarco Felsch struct da9062_pctl *pctl = gpiochip_get_data(gc); 23356cc3af4SMarco Felsch struct da9062 *da9062 = pctl->da9062; 23456cc3af4SMarco Felsch 23556cc3af4SMarco Felsch return regmap_irq_get_virq(da9062->regmap_irq, 23656cc3af4SMarco Felsch DA9062_IRQ_GPI0 + offset); 23756cc3af4SMarco Felsch } 23856cc3af4SMarco Felsch 23956cc3af4SMarco Felsch static const struct gpio_chip reference_gc = { 24056cc3af4SMarco Felsch .owner = THIS_MODULE, 24156cc3af4SMarco Felsch .get = da9062_gpio_get, 24256cc3af4SMarco Felsch .set = da9062_gpio_set, 24356cc3af4SMarco Felsch .get_direction = da9062_gpio_get_direction, 24456cc3af4SMarco Felsch .direction_input = da9062_gpio_direction_input, 24556cc3af4SMarco Felsch .direction_output = da9062_gpio_direction_output, 24656cc3af4SMarco Felsch .set_config = da9062_gpio_set_config, 24756cc3af4SMarco Felsch .to_irq = da9062_gpio_to_irq, 24856cc3af4SMarco Felsch .can_sleep = true, 24956cc3af4SMarco Felsch .ngpio = DA9062_GPIO_NUM, 25056cc3af4SMarco Felsch .base = -1, 25156cc3af4SMarco Felsch }; 25256cc3af4SMarco Felsch 25356cc3af4SMarco Felsch static int da9062_pctl_probe(struct platform_device *pdev) 25456cc3af4SMarco Felsch { 25556cc3af4SMarco Felsch struct device *parent = pdev->dev.parent; 25656cc3af4SMarco Felsch struct da9062_pctl *pctl; 25756cc3af4SMarco Felsch int i; 25856cc3af4SMarco Felsch 25956cc3af4SMarco Felsch pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); 26056cc3af4SMarco Felsch if (!pctl) 26156cc3af4SMarco Felsch return -ENOMEM; 26256cc3af4SMarco Felsch 26356cc3af4SMarco Felsch pctl->da9062 = dev_get_drvdata(parent); 26456cc3af4SMarco Felsch if (!pctl->da9062) 26556cc3af4SMarco Felsch return -EINVAL; 26656cc3af4SMarco Felsch 26756cc3af4SMarco Felsch if (!device_property_present(parent, "gpio-controller")) 26856cc3af4SMarco Felsch return 0; 26956cc3af4SMarco Felsch 27056cc3af4SMarco Felsch for (i = 0; i < ARRAY_SIZE(pctl->pin_config); i++) 27156cc3af4SMarco Felsch pctl->pin_config[i] = DA9062_PIN_GPO_PP; 27256cc3af4SMarco Felsch 27356cc3af4SMarco Felsch /* 27456cc3af4SMarco Felsch * Currently the driver handles only the GPIO support. The 27556cc3af4SMarco Felsch * pinctrl/pinmux support can be added later if needed. 27656cc3af4SMarco Felsch */ 27756cc3af4SMarco Felsch pctl->gc = reference_gc; 27856cc3af4SMarco Felsch pctl->gc.label = dev_name(&pdev->dev); 27956cc3af4SMarco Felsch pctl->gc.parent = &pdev->dev; 28056cc3af4SMarco Felsch #ifdef CONFIG_OF_GPIO 28156cc3af4SMarco Felsch pctl->gc.of_node = parent->of_node; 28256cc3af4SMarco Felsch #endif 28356cc3af4SMarco Felsch 28456cc3af4SMarco Felsch platform_set_drvdata(pdev, pctl); 28556cc3af4SMarco Felsch 28656cc3af4SMarco Felsch return devm_gpiochip_add_data(&pdev->dev, &pctl->gc, pctl); 28756cc3af4SMarco Felsch } 28856cc3af4SMarco Felsch 28956cc3af4SMarco Felsch static struct platform_driver da9062_pctl_driver = { 29056cc3af4SMarco Felsch .probe = da9062_pctl_probe, 29156cc3af4SMarco Felsch .driver = { 29256cc3af4SMarco Felsch .name = "da9062-gpio", 29356cc3af4SMarco Felsch }, 29456cc3af4SMarco Felsch }; 29556cc3af4SMarco Felsch module_platform_driver(da9062_pctl_driver); 29656cc3af4SMarco Felsch 29756cc3af4SMarco Felsch MODULE_AUTHOR("Marco Felsch <kernel@pengutronix.de>"); 29856cc3af4SMarco Felsch MODULE_DESCRIPTION("DA9062 PMIC pinctrl and GPIO Driver"); 29956cc3af4SMarco Felsch MODULE_LICENSE("GPL v2"); 30056cc3af4SMarco Felsch MODULE_ALIAS("platform:da9062-gpio"); 301