1*6b367741SMatti Vaittinen // SPDX-License-Identifier: GPL-2.0 2*6b367741SMatti Vaittinen /* 3*6b367741SMatti Vaittinen * Support to GPIOs on ROHM BD72720 and BD79300 4*6b367741SMatti Vaittinen * Copyright 2025 ROHM Semiconductors. 5*6b367741SMatti Vaittinen * Author: Matti Vaittinen <mazziesaccount@gmail.com> 6*6b367741SMatti Vaittinen */ 7*6b367741SMatti Vaittinen 8*6b367741SMatti Vaittinen #include <linux/gpio/driver.h> 9*6b367741SMatti Vaittinen #include <linux/init.h> 10*6b367741SMatti Vaittinen #include <linux/irq.h> 11*6b367741SMatti Vaittinen #include <linux/module.h> 12*6b367741SMatti Vaittinen #include <linux/of.h> 13*6b367741SMatti Vaittinen #include <linux/platform_device.h> 14*6b367741SMatti Vaittinen #include <linux/mfd/rohm-bd72720.h> 15*6b367741SMatti Vaittinen 16*6b367741SMatti Vaittinen #define BD72720_GPIO_OPEN_DRAIN 0 17*6b367741SMatti Vaittinen #define BD72720_GPIO_CMOS BIT(1) 18*6b367741SMatti Vaittinen #define BD72720_INT_GPIO1_IN_SRC 4 19*6b367741SMatti Vaittinen /* 20*6b367741SMatti Vaittinen * The BD72720 has several "one time programmable" (OTP) configurations which 21*6b367741SMatti Vaittinen * can be set at manufacturing phase. A set of these options allow using pins 22*6b367741SMatti Vaittinen * as GPIO. The OTP configuration can't be read at run-time, so drivers rely on 23*6b367741SMatti Vaittinen * device-tree to advertise the correct options. 24*6b367741SMatti Vaittinen * 25*6b367741SMatti Vaittinen * Both DVS[0,1] pins can be configured to be used for: 26*6b367741SMatti Vaittinen * - OTP0: regulator RUN state control 27*6b367741SMatti Vaittinen * - OTP1: GPI 28*6b367741SMatti Vaittinen * - OTP2: GPO 29*6b367741SMatti Vaittinen * - OTP3: Power sequencer output 30*6b367741SMatti Vaittinen * Data-sheet also states that these PINs can always be used for IRQ but the 31*6b367741SMatti Vaittinen * driver limits this by allowing them to be used for IRQs with OTP1 only. 32*6b367741SMatti Vaittinen * 33*6b367741SMatti Vaittinen * Pins GPIO_EXTEN0 (GPIO3), GPIO_EXTEN1 (GPIO4), GPIO_FAULT_B (GPIO5) have OTP 34*6b367741SMatti Vaittinen * options for a specific (non GPIO) purposes, but also an option to configure 35*6b367741SMatti Vaittinen * them to be used as a GPO. 36*6b367741SMatti Vaittinen * 37*6b367741SMatti Vaittinen * OTP settings can be separately configured for each pin. 38*6b367741SMatti Vaittinen * 39*6b367741SMatti Vaittinen * DT properties: 40*6b367741SMatti Vaittinen * "rohm,pin-dvs0" and "rohm,pin-dvs1" can be set to one of the values: 41*6b367741SMatti Vaittinen * "dvs-input", "gpi", "gpo". 42*6b367741SMatti Vaittinen * 43*6b367741SMatti Vaittinen * "rohm,pin-exten0", "rohm,pin-exten1" and "rohm,pin-fault_b" can be set to: 44*6b367741SMatti Vaittinen * "gpo" 45*6b367741SMatti Vaittinen */ 46*6b367741SMatti Vaittinen 47*6b367741SMatti Vaittinen enum bd72720_gpio_state { 48*6b367741SMatti Vaittinen BD72720_PIN_UNKNOWN, 49*6b367741SMatti Vaittinen BD72720_PIN_GPI, 50*6b367741SMatti Vaittinen BD72720_PIN_GPO, 51*6b367741SMatti Vaittinen }; 52*6b367741SMatti Vaittinen 53*6b367741SMatti Vaittinen enum { 54*6b367741SMatti Vaittinen BD72720_GPIO1, 55*6b367741SMatti Vaittinen BD72720_GPIO2, 56*6b367741SMatti Vaittinen BD72720_GPIO3, 57*6b367741SMatti Vaittinen BD72720_GPIO4, 58*6b367741SMatti Vaittinen BD72720_GPIO5, 59*6b367741SMatti Vaittinen BD72720_GPIO_EPDEN, 60*6b367741SMatti Vaittinen BD72720_NUM_GPIOS 61*6b367741SMatti Vaittinen }; 62*6b367741SMatti Vaittinen 63*6b367741SMatti Vaittinen struct bd72720_gpio { 64*6b367741SMatti Vaittinen /* chip.parent points the MFD which provides DT node and regmap */ 65*6b367741SMatti Vaittinen struct gpio_chip chip; 66*6b367741SMatti Vaittinen /* dev points to the platform device for devm and prints */ 67*6b367741SMatti Vaittinen struct device *dev; 68*6b367741SMatti Vaittinen struct regmap *regmap; 69*6b367741SMatti Vaittinen int gpio_is_input; 70*6b367741SMatti Vaittinen }; 71*6b367741SMatti Vaittinen 72*6b367741SMatti Vaittinen static int bd72720gpi_get(struct bd72720_gpio *bdgpio, unsigned int reg_offset) 73*6b367741SMatti Vaittinen { 74*6b367741SMatti Vaittinen int ret, val, shift; 75*6b367741SMatti Vaittinen 76*6b367741SMatti Vaittinen ret = regmap_read(bdgpio->regmap, BD72720_REG_INT_ETC1_SRC, &val); 77*6b367741SMatti Vaittinen if (ret) 78*6b367741SMatti Vaittinen return ret; 79*6b367741SMatti Vaittinen 80*6b367741SMatti Vaittinen shift = BD72720_INT_GPIO1_IN_SRC + reg_offset; 81*6b367741SMatti Vaittinen 82*6b367741SMatti Vaittinen return (val >> shift) & 1; 83*6b367741SMatti Vaittinen } 84*6b367741SMatti Vaittinen 85*6b367741SMatti Vaittinen static int bd72720gpo_get(struct bd72720_gpio *bdgpio, 86*6b367741SMatti Vaittinen unsigned int offset) 87*6b367741SMatti Vaittinen { 88*6b367741SMatti Vaittinen const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL, 89*6b367741SMatti Vaittinen BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL, 90*6b367741SMatti Vaittinen BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL }; 91*6b367741SMatti Vaittinen int ret, val; 92*6b367741SMatti Vaittinen 93*6b367741SMatti Vaittinen ret = regmap_read(bdgpio->regmap, regs[offset], &val); 94*6b367741SMatti Vaittinen if (ret) 95*6b367741SMatti Vaittinen return ret; 96*6b367741SMatti Vaittinen 97*6b367741SMatti Vaittinen return val & BD72720_GPIO_HIGH; 98*6b367741SMatti Vaittinen } 99*6b367741SMatti Vaittinen 100*6b367741SMatti Vaittinen static int bd72720gpio_get(struct gpio_chip *chip, unsigned int offset) 101*6b367741SMatti Vaittinen { 102*6b367741SMatti Vaittinen struct bd72720_gpio *bdgpio = gpiochip_get_data(chip); 103*6b367741SMatti Vaittinen 104*6b367741SMatti Vaittinen if (BIT(offset) & bdgpio->gpio_is_input) 105*6b367741SMatti Vaittinen return bd72720gpi_get(bdgpio, offset); 106*6b367741SMatti Vaittinen 107*6b367741SMatti Vaittinen return bd72720gpo_get(bdgpio, offset); 108*6b367741SMatti Vaittinen } 109*6b367741SMatti Vaittinen 110*6b367741SMatti Vaittinen static int bd72720gpo_set(struct gpio_chip *chip, unsigned int offset, 111*6b367741SMatti Vaittinen int value) 112*6b367741SMatti Vaittinen { 113*6b367741SMatti Vaittinen struct bd72720_gpio *bdgpio = gpiochip_get_data(chip); 114*6b367741SMatti Vaittinen const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL, 115*6b367741SMatti Vaittinen BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL, 116*6b367741SMatti Vaittinen BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL }; 117*6b367741SMatti Vaittinen 118*6b367741SMatti Vaittinen if (BIT(offset) & bdgpio->gpio_is_input) { 119*6b367741SMatti Vaittinen dev_dbg(bdgpio->dev, "pin %d not output.\n", offset); 120*6b367741SMatti Vaittinen return -EINVAL; 121*6b367741SMatti Vaittinen } 122*6b367741SMatti Vaittinen 123*6b367741SMatti Vaittinen if (value) 124*6b367741SMatti Vaittinen return regmap_set_bits(bdgpio->regmap, regs[offset], 125*6b367741SMatti Vaittinen BD72720_GPIO_HIGH); 126*6b367741SMatti Vaittinen 127*6b367741SMatti Vaittinen return regmap_clear_bits(bdgpio->regmap, regs[offset], 128*6b367741SMatti Vaittinen BD72720_GPIO_HIGH); 129*6b367741SMatti Vaittinen } 130*6b367741SMatti Vaittinen 131*6b367741SMatti Vaittinen static int bd72720_gpio_set_config(struct gpio_chip *chip, unsigned int offset, 132*6b367741SMatti Vaittinen unsigned long config) 133*6b367741SMatti Vaittinen { 134*6b367741SMatti Vaittinen struct bd72720_gpio *bdgpio = gpiochip_get_data(chip); 135*6b367741SMatti Vaittinen const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL, 136*6b367741SMatti Vaittinen BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL, 137*6b367741SMatti Vaittinen BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL }; 138*6b367741SMatti Vaittinen 139*6b367741SMatti Vaittinen /* 140*6b367741SMatti Vaittinen * We can only set the output mode, which makes sense only when output 141*6b367741SMatti Vaittinen * OTP configuration is used. 142*6b367741SMatti Vaittinen */ 143*6b367741SMatti Vaittinen if (BIT(offset) & bdgpio->gpio_is_input) 144*6b367741SMatti Vaittinen return -ENOTSUPP; 145*6b367741SMatti Vaittinen 146*6b367741SMatti Vaittinen switch (pinconf_to_config_param(config)) { 147*6b367741SMatti Vaittinen case PIN_CONFIG_DRIVE_OPEN_DRAIN: 148*6b367741SMatti Vaittinen return regmap_update_bits(bdgpio->regmap, 149*6b367741SMatti Vaittinen regs[offset], 150*6b367741SMatti Vaittinen BD72720_GPIO_DRIVE_MASK, 151*6b367741SMatti Vaittinen BD72720_GPIO_OPEN_DRAIN); 152*6b367741SMatti Vaittinen case PIN_CONFIG_DRIVE_PUSH_PULL: 153*6b367741SMatti Vaittinen return regmap_update_bits(bdgpio->regmap, 154*6b367741SMatti Vaittinen regs[offset], 155*6b367741SMatti Vaittinen BD72720_GPIO_DRIVE_MASK, 156*6b367741SMatti Vaittinen BD72720_GPIO_CMOS); 157*6b367741SMatti Vaittinen default: 158*6b367741SMatti Vaittinen break; 159*6b367741SMatti Vaittinen } 160*6b367741SMatti Vaittinen 161*6b367741SMatti Vaittinen return -ENOTSUPP; 162*6b367741SMatti Vaittinen } 163*6b367741SMatti Vaittinen 164*6b367741SMatti Vaittinen static int bd72720gpo_direction_get(struct gpio_chip *chip, 165*6b367741SMatti Vaittinen unsigned int offset) 166*6b367741SMatti Vaittinen { 167*6b367741SMatti Vaittinen struct bd72720_gpio *bdgpio = gpiochip_get_data(chip); 168*6b367741SMatti Vaittinen 169*6b367741SMatti Vaittinen if (BIT(offset) & bdgpio->gpio_is_input) 170*6b367741SMatti Vaittinen return GPIO_LINE_DIRECTION_IN; 171*6b367741SMatti Vaittinen 172*6b367741SMatti Vaittinen return GPIO_LINE_DIRECTION_OUT; 173*6b367741SMatti Vaittinen } 174*6b367741SMatti Vaittinen 175*6b367741SMatti Vaittinen static int bd72720_valid_mask(struct gpio_chip *gc, 176*6b367741SMatti Vaittinen unsigned long *valid_mask, 177*6b367741SMatti Vaittinen unsigned int ngpios) 178*6b367741SMatti Vaittinen { 179*6b367741SMatti Vaittinen static const char * const properties[] = { 180*6b367741SMatti Vaittinen "rohm,pin-dvs0", "rohm,pin-dvs1", "rohm,pin-exten0", 181*6b367741SMatti Vaittinen "rohm,pin-exten1", "rohm,pin-fault_b" 182*6b367741SMatti Vaittinen }; 183*6b367741SMatti Vaittinen struct bd72720_gpio *g = gpiochip_get_data(gc); 184*6b367741SMatti Vaittinen const char *val; 185*6b367741SMatti Vaittinen int i, ret; 186*6b367741SMatti Vaittinen 187*6b367741SMatti Vaittinen *valid_mask = BIT(BD72720_GPIO_EPDEN); 188*6b367741SMatti Vaittinen 189*6b367741SMatti Vaittinen if (!gc->parent) 190*6b367741SMatti Vaittinen return 0; 191*6b367741SMatti Vaittinen 192*6b367741SMatti Vaittinen for (i = 0; i < ARRAY_SIZE(properties); i++) { 193*6b367741SMatti Vaittinen ret = fwnode_property_read_string(dev_fwnode(gc->parent), 194*6b367741SMatti Vaittinen properties[i], &val); 195*6b367741SMatti Vaittinen 196*6b367741SMatti Vaittinen if (ret) { 197*6b367741SMatti Vaittinen if (ret == -EINVAL) 198*6b367741SMatti Vaittinen continue; 199*6b367741SMatti Vaittinen 200*6b367741SMatti Vaittinen dev_err(g->dev, "pin %d (%s), bad configuration\n", i, 201*6b367741SMatti Vaittinen properties[i]); 202*6b367741SMatti Vaittinen 203*6b367741SMatti Vaittinen return ret; 204*6b367741SMatti Vaittinen } 205*6b367741SMatti Vaittinen 206*6b367741SMatti Vaittinen if (strcmp(val, "gpi") == 0) { 207*6b367741SMatti Vaittinen if (i != BD72720_GPIO1 && i != BD72720_GPIO2) { 208*6b367741SMatti Vaittinen dev_warn(g->dev, 209*6b367741SMatti Vaittinen "pin %d (%s) does not support INPUT mode", 210*6b367741SMatti Vaittinen i, properties[i]); 211*6b367741SMatti Vaittinen continue; 212*6b367741SMatti Vaittinen } 213*6b367741SMatti Vaittinen 214*6b367741SMatti Vaittinen *valid_mask |= BIT(i); 215*6b367741SMatti Vaittinen g->gpio_is_input |= BIT(i); 216*6b367741SMatti Vaittinen } else if (strcmp(val, "gpo") == 0) { 217*6b367741SMatti Vaittinen *valid_mask |= BIT(i); 218*6b367741SMatti Vaittinen } 219*6b367741SMatti Vaittinen } 220*6b367741SMatti Vaittinen 221*6b367741SMatti Vaittinen return 0; 222*6b367741SMatti Vaittinen } 223*6b367741SMatti Vaittinen 224*6b367741SMatti Vaittinen /* Template for GPIO chip */ 225*6b367741SMatti Vaittinen static const struct gpio_chip bd72720gpo_chip = { 226*6b367741SMatti Vaittinen .label = "bd72720", 227*6b367741SMatti Vaittinen .owner = THIS_MODULE, 228*6b367741SMatti Vaittinen .get = bd72720gpio_get, 229*6b367741SMatti Vaittinen .get_direction = bd72720gpo_direction_get, 230*6b367741SMatti Vaittinen .set = bd72720gpo_set, 231*6b367741SMatti Vaittinen .set_config = bd72720_gpio_set_config, 232*6b367741SMatti Vaittinen .init_valid_mask = bd72720_valid_mask, 233*6b367741SMatti Vaittinen .can_sleep = true, 234*6b367741SMatti Vaittinen .ngpio = BD72720_NUM_GPIOS, 235*6b367741SMatti Vaittinen .base = -1, 236*6b367741SMatti Vaittinen }; 237*6b367741SMatti Vaittinen 238*6b367741SMatti Vaittinen static int gpo_bd72720_probe(struct platform_device *pdev) 239*6b367741SMatti Vaittinen { 240*6b367741SMatti Vaittinen struct bd72720_gpio *g; 241*6b367741SMatti Vaittinen struct device *parent, *dev; 242*6b367741SMatti Vaittinen 243*6b367741SMatti Vaittinen /* 244*6b367741SMatti Vaittinen * Bind devm lifetime to this platform device => use dev for devm. 245*6b367741SMatti Vaittinen * also the prints should originate from this device. 246*6b367741SMatti Vaittinen */ 247*6b367741SMatti Vaittinen dev = &pdev->dev; 248*6b367741SMatti Vaittinen /* The device-tree and regmap come from MFD => use parent for that */ 249*6b367741SMatti Vaittinen parent = dev->parent; 250*6b367741SMatti Vaittinen 251*6b367741SMatti Vaittinen g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL); 252*6b367741SMatti Vaittinen if (!g) 253*6b367741SMatti Vaittinen return -ENOMEM; 254*6b367741SMatti Vaittinen 255*6b367741SMatti Vaittinen g->chip = bd72720gpo_chip; 256*6b367741SMatti Vaittinen g->dev = dev; 257*6b367741SMatti Vaittinen g->chip.parent = parent; 258*6b367741SMatti Vaittinen g->regmap = dev_get_regmap(parent, NULL); 259*6b367741SMatti Vaittinen 260*6b367741SMatti Vaittinen return devm_gpiochip_add_data(dev, &g->chip, g); 261*6b367741SMatti Vaittinen } 262*6b367741SMatti Vaittinen 263*6b367741SMatti Vaittinen static const struct platform_device_id bd72720_gpio_id[] = { 264*6b367741SMatti Vaittinen { "bd72720-gpio" }, 265*6b367741SMatti Vaittinen { }, 266*6b367741SMatti Vaittinen }; 267*6b367741SMatti Vaittinen MODULE_DEVICE_TABLE(platform, bd72720_gpio_id); 268*6b367741SMatti Vaittinen 269*6b367741SMatti Vaittinen static struct platform_driver gpo_bd72720_driver = { 270*6b367741SMatti Vaittinen .driver = { 271*6b367741SMatti Vaittinen .name = "bd72720-gpio", 272*6b367741SMatti Vaittinen .probe_type = PROBE_PREFER_ASYNCHRONOUS, 273*6b367741SMatti Vaittinen }, 274*6b367741SMatti Vaittinen .probe = gpo_bd72720_probe, 275*6b367741SMatti Vaittinen .id_table = bd72720_gpio_id, 276*6b367741SMatti Vaittinen }; 277*6b367741SMatti Vaittinen module_platform_driver(gpo_bd72720_driver); 278*6b367741SMatti Vaittinen 279*6b367741SMatti Vaittinen MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 280*6b367741SMatti Vaittinen MODULE_DESCRIPTION("GPIO interface for BD72720 and BD73900"); 281*6b367741SMatti Vaittinen MODULE_LICENSE("GPL"); 282