1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Support to GPOs on ROHM BD71815 4 * Copyright 2021 ROHM Semiconductors. 5 * Author: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> 6 * 7 * Copyright 2014 Embest Technology Co. Ltd. Inc. 8 * Author: yanglsh@embest-tech.com 9 */ 10 11 #include <linux/gpio/driver.h> 12 #include <linux/init.h> 13 #include <linux/irq.h> 14 #include <linux/module.h> 15 #include <linux/of.h> 16 #include <linux/platform_device.h> 17 /* For the BD71815 register definitions */ 18 #include <linux/mfd/rohm-bd71815.h> 19 20 struct bd71815_gpio { 21 /* chip.parent points the MFD which provides DT node and regmap */ 22 struct gpio_chip chip; 23 /* dev points to the platform device for devm and prints */ 24 struct device *dev; 25 struct regmap *regmap; 26 }; 27 28 static int bd71815gpo_get(struct gpio_chip *chip, unsigned int offset) 29 { 30 struct bd71815_gpio *bd71815 = gpiochip_get_data(chip); 31 int ret, val; 32 33 ret = regmap_read(bd71815->regmap, BD71815_REG_GPO, &val); 34 if (ret) 35 return ret; 36 37 return (val >> offset) & 1; 38 } 39 40 static int bd71815gpo_set(struct gpio_chip *chip, unsigned int offset, 41 int value) 42 { 43 struct bd71815_gpio *bd71815 = gpiochip_get_data(chip); 44 int bit; 45 46 bit = BIT(offset); 47 48 if (value) 49 return regmap_set_bits(bd71815->regmap, BD71815_REG_GPO, bit); 50 51 return regmap_clear_bits(bd71815->regmap, BD71815_REG_GPO, bit); 52 } 53 54 static int bd71815_gpio_set_config(struct gpio_chip *chip, unsigned int offset, 55 unsigned long config) 56 { 57 struct bd71815_gpio *bdgpio = gpiochip_get_data(chip); 58 59 switch (pinconf_to_config_param(config)) { 60 case PIN_CONFIG_DRIVE_OPEN_DRAIN: 61 return regmap_update_bits(bdgpio->regmap, 62 BD71815_REG_GPO, 63 BD71815_GPIO_DRIVE_MASK << offset, 64 BD71815_GPIO_OPEN_DRAIN << offset); 65 case PIN_CONFIG_DRIVE_PUSH_PULL: 66 return regmap_update_bits(bdgpio->regmap, 67 BD71815_REG_GPO, 68 BD71815_GPIO_DRIVE_MASK << offset, 69 BD71815_GPIO_CMOS << offset); 70 default: 71 break; 72 } 73 return -ENOTSUPP; 74 } 75 76 /* BD71815 GPIO is actually GPO */ 77 static int bd71815gpo_direction_get(struct gpio_chip *gc, unsigned int offset) 78 { 79 return GPIO_LINE_DIRECTION_OUT; 80 } 81 82 /* Template for GPIO chip */ 83 static const struct gpio_chip bd71815gpo_chip = { 84 .label = "bd71815", 85 .owner = THIS_MODULE, 86 .get = bd71815gpo_get, 87 .get_direction = bd71815gpo_direction_get, 88 .set_rv = bd71815gpo_set, 89 .set_config = bd71815_gpio_set_config, 90 .can_sleep = true, 91 }; 92 93 #define BD71815_TWO_GPIOS GENMASK(1, 0) 94 #define BD71815_ONE_GPIO BIT(0) 95 96 /* 97 * Sigh. The BD71815 and BD71817 were originally designed to support two GPO 98 * pins. At some point it was noticed the second GPO pin which is the E5 pin 99 * located at the center of IC is hard to use on PCB (due to the location). It 100 * was decided to not promote this second GPO and the pin is marked as GND in 101 * the datasheet. The functionality is still there though! I guess driving a GPO 102 * connected to the ground is a bad idea. Thus we do not support it by default. 103 * OTOH - the original driver written by colleagues at Embest did support 104 * controlling this second GPO. It is thus possible this is used in some of the 105 * products. 106 * 107 * This driver does not by default support configuring this second GPO 108 * but allows using it by providing the DT property 109 * "rohm,enable-hidden-gpo". 110 */ 111 static int bd71815_init_valid_mask(struct gpio_chip *gc, 112 unsigned long *valid_mask, 113 unsigned int ngpios) 114 { 115 if (ngpios != 2) 116 return 0; 117 118 if (gc->parent && device_property_present(gc->parent, 119 "rohm,enable-hidden-gpo")) 120 *valid_mask = BD71815_TWO_GPIOS; 121 else 122 *valid_mask = BD71815_ONE_GPIO; 123 124 return 0; 125 } 126 127 static int gpo_bd71815_probe(struct platform_device *pdev) 128 { 129 struct bd71815_gpio *g; 130 struct device *parent, *dev; 131 132 /* 133 * Bind devm lifetime to this platform device => use dev for devm. 134 * also the prints should originate from this device. 135 */ 136 dev = &pdev->dev; 137 /* The device-tree and regmap come from MFD => use parent for that */ 138 parent = dev->parent; 139 140 g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL); 141 if (!g) 142 return -ENOMEM; 143 144 g->chip = bd71815gpo_chip; 145 146 /* 147 * FIXME: As writing of this the sysfs interface for GPIO control does 148 * not respect the valid_mask. Do not trust it but rather set the ngpios 149 * to 1 if "rohm,enable-hidden-gpo" is not given. 150 * 151 * This check can be removed later if the sysfs export is fixed and 152 * if the fix is backported. 153 * 154 * For now it is safest to just set the ngpios though. 155 */ 156 if (device_property_present(parent, "rohm,enable-hidden-gpo")) 157 g->chip.ngpio = 2; 158 else 159 g->chip.ngpio = 1; 160 161 g->chip.init_valid_mask = bd71815_init_valid_mask; 162 g->chip.base = -1; 163 g->chip.parent = parent; 164 g->regmap = dev_get_regmap(parent, NULL); 165 g->dev = dev; 166 167 return devm_gpiochip_add_data(dev, &g->chip, g); 168 } 169 170 static struct platform_driver gpo_bd71815_driver = { 171 .driver = { 172 .name = "bd71815-gpo", 173 }, 174 .probe = gpo_bd71815_probe, 175 }; 176 module_platform_driver(gpo_bd71815_driver); 177 178 MODULE_ALIAS("platform:bd71815-gpo"); 179 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 180 MODULE_AUTHOR("Peter Yang <yanglsh@embest-tech.com>"); 181 MODULE_DESCRIPTION("GPO interface for BD71815"); 182 MODULE_LICENSE("GPL"); 183