gpio-bd71828.c (3897B)
1// SPDX-License-Identifier: GPL-2.0-only 2// Copyright (C) 2018 ROHM Semiconductors 3 4#include <linux/gpio/driver.h> 5#include <linux/mfd/rohm-bd71828.h> 6#include <linux/module.h> 7#include <linux/platform_device.h> 8#include <linux/regmap.h> 9 10#define GPIO_OUT_REG(off) (BD71828_REG_GPIO_CTRL1 + (off)) 11#define HALL_GPIO_OFFSET 3 12 13struct bd71828_gpio { 14 struct regmap *regmap; 15 struct device *dev; 16 struct gpio_chip gpio; 17}; 18 19static void bd71828_gpio_set(struct gpio_chip *chip, unsigned int offset, 20 int value) 21{ 22 int ret; 23 struct bd71828_gpio *bdgpio = gpiochip_get_data(chip); 24 u8 val = (value) ? BD71828_GPIO_OUT_HI : BD71828_GPIO_OUT_LO; 25 26 /* 27 * The HALL input pin can only be used as input. If this is the pin 28 * we are dealing with - then we are done 29 */ 30 if (offset == HALL_GPIO_OFFSET) 31 return; 32 33 ret = regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset), 34 BD71828_GPIO_OUT_MASK, val); 35 if (ret) 36 dev_err(bdgpio->dev, "Could not set gpio to %d\n", value); 37} 38 39static int bd71828_gpio_get(struct gpio_chip *chip, unsigned int offset) 40{ 41 int ret; 42 unsigned int val; 43 struct bd71828_gpio *bdgpio = gpiochip_get_data(chip); 44 45 if (offset == HALL_GPIO_OFFSET) 46 ret = regmap_read(bdgpio->regmap, BD71828_REG_IO_STAT, 47 &val); 48 else 49 ret = regmap_read(bdgpio->regmap, GPIO_OUT_REG(offset), 50 &val); 51 if (!ret) 52 ret = (val & BD71828_GPIO_OUT_MASK); 53 54 return ret; 55} 56 57static int bd71828_gpio_set_config(struct gpio_chip *chip, unsigned int offset, 58 unsigned long config) 59{ 60 struct bd71828_gpio *bdgpio = gpiochip_get_data(chip); 61 62 if (offset == HALL_GPIO_OFFSET) 63 return -ENOTSUPP; 64 65 switch (pinconf_to_config_param(config)) { 66 case PIN_CONFIG_DRIVE_OPEN_DRAIN: 67 return regmap_update_bits(bdgpio->regmap, 68 GPIO_OUT_REG(offset), 69 BD71828_GPIO_DRIVE_MASK, 70 BD71828_GPIO_OPEN_DRAIN); 71 case PIN_CONFIG_DRIVE_PUSH_PULL: 72 return regmap_update_bits(bdgpio->regmap, 73 GPIO_OUT_REG(offset), 74 BD71828_GPIO_DRIVE_MASK, 75 BD71828_GPIO_PUSH_PULL); 76 default: 77 break; 78 } 79 return -ENOTSUPP; 80} 81 82static int bd71828_get_direction(struct gpio_chip *chip, unsigned int offset) 83{ 84 /* 85 * Pin usage is selected by OTP data. We can't read it runtime. Hence 86 * we trust that if the pin is not excluded by "gpio-reserved-ranges" 87 * the OTP configuration is set to OUT. (Other pins but HALL input pin 88 * on BD71828 can't really be used for general purpose input - input 89 * states are used for specific cases like regulator control or 90 * PMIC_ON_REQ. 91 */ 92 if (offset == HALL_GPIO_OFFSET) 93 return GPIO_LINE_DIRECTION_IN; 94 95 return GPIO_LINE_DIRECTION_OUT; 96} 97 98static int bd71828_probe(struct platform_device *pdev) 99{ 100 struct device *dev = &pdev->dev; 101 struct bd71828_gpio *bdgpio; 102 103 bdgpio = devm_kzalloc(dev, sizeof(*bdgpio), GFP_KERNEL); 104 if (!bdgpio) 105 return -ENOMEM; 106 107 bdgpio->dev = dev; 108 bdgpio->gpio.parent = dev->parent; 109 bdgpio->gpio.label = "bd71828-gpio"; 110 bdgpio->gpio.owner = THIS_MODULE; 111 bdgpio->gpio.get_direction = bd71828_get_direction; 112 bdgpio->gpio.set_config = bd71828_gpio_set_config; 113 bdgpio->gpio.can_sleep = true; 114 bdgpio->gpio.get = bd71828_gpio_get; 115 bdgpio->gpio.set = bd71828_gpio_set; 116 bdgpio->gpio.base = -1; 117 118 /* 119 * See if we need some implementation to mark some PINs as 120 * not controllable based on DT info or if core can handle 121 * "gpio-reserved-ranges" and exclude them from control 122 */ 123 bdgpio->gpio.ngpio = 4; 124 bdgpio->regmap = dev_get_regmap(dev->parent, NULL); 125 if (!bdgpio->regmap) 126 return -ENODEV; 127 128 return devm_gpiochip_add_data(dev, &bdgpio->gpio, bdgpio); 129} 130 131static struct platform_driver bd71828_gpio = { 132 .driver = { 133 .name = "bd71828-gpio" 134 }, 135 .probe = bd71828_probe, 136}; 137 138module_platform_driver(bd71828_gpio); 139 140MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 141MODULE_DESCRIPTION("BD71828 voltage regulator driver"); 142MODULE_LICENSE("GPL"); 143MODULE_ALIAS("platform:bd71828-gpio");