1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright 2025 Bootlin 4 * 5 * Author: Kamel BOUHARA <kamel.bouhara@bootlin.com> 6 * Author: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com> 7 */ 8 9 #include <linux/bitfield.h> 10 #include <linux/bitmap.h> 11 #include <linux/err.h> 12 #include <linux/gpio/driver.h> 13 #include <linux/gpio/regmap.h> 14 #include <linux/init.h> 15 #include <linux/interrupt.h> 16 #include <linux/mfd/max7360.h> 17 #include <linux/minmax.h> 18 #include <linux/module.h> 19 #include <linux/platform_device.h> 20 #include <linux/property.h> 21 #include <linux/regmap.h> 22 23 #define MAX7360_GPIO_PORT 1 24 #define MAX7360_GPIO_COL 2 25 26 struct max7360_gpio_plat_data { 27 unsigned int function; 28 }; 29 30 static struct max7360_gpio_plat_data max7360_gpio_port_plat = { .function = MAX7360_GPIO_PORT }; 31 static struct max7360_gpio_plat_data max7360_gpio_col_plat = { .function = MAX7360_GPIO_COL }; 32 33 static int max7360_get_available_gpos(struct device *dev, unsigned int *available_gpios) 34 { 35 u32 columns; 36 int ret; 37 38 ret = device_property_read_u32(dev->parent, "keypad,num-columns", &columns); 39 if (ret) { 40 dev_err(dev, "Failed to read columns count\n"); 41 return ret; 42 } 43 44 *available_gpios = min(MAX7360_MAX_GPO, MAX7360_MAX_KEY_COLS - columns); 45 46 return 0; 47 } 48 49 static int max7360_gpo_init_valid_mask(struct gpio_chip *gc, 50 unsigned long *valid_mask, 51 unsigned int ngpios) 52 { 53 unsigned int available_gpios; 54 int ret; 55 56 ret = max7360_get_available_gpos(gc->parent, &available_gpios); 57 if (ret) 58 return ret; 59 60 bitmap_clear(valid_mask, 0, MAX7360_MAX_KEY_COLS - available_gpios); 61 62 return 0; 63 } 64 65 static int max7360_set_gpos_count(struct device *dev, struct regmap *regmap) 66 { 67 /* 68 * MAX7360 COL0 to COL7 pins can be used either as keypad columns, 69 * general purpose output or a mix of both. 70 * By default, all pins are used as keypad, here we update this 71 * configuration to allow to use some of them as GPIOs. 72 */ 73 unsigned int available_gpios; 74 unsigned int val; 75 int ret; 76 77 ret = max7360_get_available_gpos(dev, &available_gpios); 78 if (ret) 79 return ret; 80 81 /* 82 * Configure which GPIOs will be used for keypad. 83 * MAX7360_REG_DEBOUNCE contains configuration both for keypad debounce 84 * timings and gpos/keypad columns repartition. Only the later is 85 * modified here. 86 */ 87 val = FIELD_PREP(MAX7360_PORTS, available_gpios); 88 ret = regmap_write_bits(regmap, MAX7360_REG_DEBOUNCE, MAX7360_PORTS, val); 89 if (ret) 90 dev_err(dev, "Failed to write max7360 columns/gpos configuration"); 91 92 return ret; 93 } 94 95 static int max7360_gpio_reg_mask_xlate(struct gpio_regmap *gpio, 96 unsigned int base, unsigned int offset, 97 unsigned int *reg, unsigned int *mask) 98 { 99 if (base == MAX7360_REG_PWMBASE) { 100 /* 101 * GPIO output is using PWM duty cycle registers: one register 102 * per line, with value being either 0 or 255. 103 */ 104 *reg = base + offset; 105 *mask = GENMASK(7, 0); 106 } else { 107 *reg = base; 108 *mask = BIT(offset); 109 } 110 111 return 0; 112 } 113 114 static const struct regmap_irq max7360_regmap_irqs[MAX7360_MAX_GPIO] = { 115 REGMAP_IRQ_REG(0, 0, BIT(0)), 116 REGMAP_IRQ_REG(1, 0, BIT(1)), 117 REGMAP_IRQ_REG(2, 0, BIT(2)), 118 REGMAP_IRQ_REG(3, 0, BIT(3)), 119 REGMAP_IRQ_REG(4, 0, BIT(4)), 120 REGMAP_IRQ_REG(5, 0, BIT(5)), 121 REGMAP_IRQ_REG(6, 0, BIT(6)), 122 REGMAP_IRQ_REG(7, 0, BIT(7)), 123 }; 124 125 static int max7360_handle_mask_sync(const int index, 126 const unsigned int mask_buf_def, 127 const unsigned int mask_buf, 128 void *const irq_drv_data) 129 { 130 struct regmap *regmap = irq_drv_data; 131 int ret; 132 133 for (unsigned int i = 0; i < MAX7360_MAX_GPIO; i++) { 134 ret = regmap_assign_bits(regmap, MAX7360_REG_PWMCFG(i), 135 MAX7360_PORT_CFG_INTERRUPT_MASK, mask_buf & BIT(i)); 136 if (ret) 137 return ret; 138 } 139 140 return 0; 141 } 142 143 static int max7360_gpio_probe(struct platform_device *pdev) 144 { 145 const struct max7360_gpio_plat_data *plat_data; 146 struct gpio_regmap_config gpio_config = { }; 147 struct regmap_irq_chip *irq_chip; 148 struct device *dev = &pdev->dev; 149 struct regmap *regmap; 150 unsigned int outconf; 151 int ret; 152 153 regmap = dev_get_regmap(dev->parent, NULL); 154 if (!regmap) 155 return dev_err_probe(dev, -ENODEV, "could not get parent regmap\n"); 156 157 plat_data = device_get_match_data(dev); 158 if (plat_data->function == MAX7360_GPIO_PORT) { 159 if (device_property_read_bool(dev, "interrupt-controller")) { 160 /* 161 * Port GPIOs with interrupt-controller property: add IRQ 162 * controller. 163 */ 164 gpio_config.regmap_irq_flags = IRQF_ONESHOT | IRQF_SHARED; 165 gpio_config.regmap_irq_line = 166 fwnode_irq_get_byname(dev_fwnode(dev->parent), "inti"); 167 if (gpio_config.regmap_irq_line < 0) 168 return dev_err_probe(dev, gpio_config.regmap_irq_line, 169 "Failed to get IRQ\n"); 170 171 /* Create custom IRQ configuration. */ 172 irq_chip = devm_kzalloc(dev, sizeof(*irq_chip), GFP_KERNEL); 173 gpio_config.regmap_irq_chip = irq_chip; 174 if (!irq_chip) 175 return -ENOMEM; 176 177 irq_chip->name = dev_name(dev); 178 irq_chip->status_base = MAX7360_REG_GPIOIN; 179 irq_chip->status_is_level = true; 180 irq_chip->num_regs = 1; 181 irq_chip->num_irqs = MAX7360_MAX_GPIO; 182 irq_chip->irqs = max7360_regmap_irqs; 183 irq_chip->handle_mask_sync = max7360_handle_mask_sync; 184 irq_chip->irq_drv_data = regmap; 185 186 for (unsigned int i = 0; i < MAX7360_MAX_GPIO; i++) { 187 ret = regmap_write_bits(regmap, MAX7360_REG_PWMCFG(i), 188 MAX7360_PORT_CFG_INTERRUPT_EDGES, 189 MAX7360_PORT_CFG_INTERRUPT_EDGES); 190 if (ret) 191 return dev_err_probe(dev, ret, 192 "Failed to enable interrupts\n"); 193 } 194 } 195 196 /* 197 * Port GPIOs: set output mode configuration (constant-current or not). 198 * This property is optional. 199 */ 200 ret = device_property_read_u32(dev, "maxim,constant-current-disable", &outconf); 201 if (!ret) { 202 ret = regmap_write(regmap, MAX7360_REG_GPIOOUTM, outconf); 203 if (ret) 204 return dev_err_probe(dev, ret, 205 "Failed to set constant-current configuration\n"); 206 } 207 } 208 209 /* Add gpio device. */ 210 gpio_config.parent = dev; 211 gpio_config.regmap = regmap; 212 if (plat_data->function == MAX7360_GPIO_PORT) { 213 gpio_config.ngpio = MAX7360_MAX_GPIO; 214 gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(MAX7360_REG_GPIOIN); 215 gpio_config.reg_set_base = GPIO_REGMAP_ADDR(MAX7360_REG_PWMBASE); 216 gpio_config.reg_dir_out_base = GPIO_REGMAP_ADDR(MAX7360_REG_GPIOCTRL); 217 gpio_config.ngpio_per_reg = MAX7360_MAX_GPIO; 218 gpio_config.reg_mask_xlate = max7360_gpio_reg_mask_xlate; 219 } else { 220 ret = max7360_set_gpos_count(dev, regmap); 221 if (ret) 222 return dev_err_probe(dev, ret, "Failed to set GPOS pin count\n"); 223 224 gpio_config.reg_set_base = GPIO_REGMAP_ADDR(MAX7360_REG_PORTS); 225 gpio_config.ngpio = MAX7360_MAX_KEY_COLS; 226 gpio_config.init_valid_mask = max7360_gpo_init_valid_mask; 227 } 228 229 return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config)); 230 } 231 232 static const struct of_device_id max7360_gpio_of_match[] = { 233 { 234 .compatible = "maxim,max7360-gpo", 235 .data = &max7360_gpio_col_plat 236 }, { 237 .compatible = "maxim,max7360-gpio", 238 .data = &max7360_gpio_port_plat 239 }, { 240 } 241 }; 242 MODULE_DEVICE_TABLE(of, max7360_gpio_of_match); 243 244 static struct platform_driver max7360_gpio_driver = { 245 .driver = { 246 .name = "max7360-gpio", 247 .of_match_table = max7360_gpio_of_match, 248 }, 249 .probe = max7360_gpio_probe, 250 }; 251 module_platform_driver(max7360_gpio_driver); 252 253 MODULE_DESCRIPTION("MAX7360 GPIO driver"); 254 MODULE_AUTHOR("Kamel BOUHARA <kamel.bouhara@bootlin.com>"); 255 MODULE_AUTHOR("Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>"); 256 MODULE_LICENSE("GPL"); 257