1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2019 VeriSilicon Limited. 4 * Copyright (C) 2025 Blaize, Inc. 5 */ 6 7 #include <linux/errno.h> 8 #include <linux/gpio/driver.h> 9 #include <linux/init.h> 10 #include <linux/interrupt.h> 11 #include <linux/io.h> 12 #include <linux/module.h> 13 #include <linux/platform_device.h> 14 #include <linux/property.h> 15 #include <linux/slab.h> 16 #include <linux/spinlock.h> 17 18 #define GPIO_DIR_REG 0x00 19 #define GPIO_CTRL_REG 0x04 20 #define GPIO_SET_REG 0x08 21 #define GPIO_CLR_REG 0x0C 22 #define GPIO_ODATA_REG 0x10 23 #define GPIO_IDATA_REG 0x14 24 #define GPIO_IEN_REG 0x18 25 #define GPIO_IS_REG 0x1C 26 #define GPIO_IBE_REG 0x20 27 #define GPIO_IEV_REG 0x24 28 #define GPIO_RIS_REG 0x28 29 #define GPIO_IM_REG 0x2C 30 #define GPIO_MIS_REG 0x30 31 #define GPIO_IC_REG 0x34 32 #define GPIO_DB_REG 0x38 33 #define GPIO_DFG_REG 0x3C 34 35 #define DRIVER_NAME "blzp1600-gpio" 36 37 struct blzp1600_gpio { 38 void __iomem *base; 39 struct gpio_chip gc; 40 int irq; 41 }; 42 43 static inline struct blzp1600_gpio *get_blzp1600_gpio_from_irq_data(struct irq_data *d) 44 { 45 return gpiochip_get_data(irq_data_get_irq_chip_data(d)); 46 } 47 48 static inline struct blzp1600_gpio *get_blzp1600_gpio_from_irq_desc(struct irq_desc *d) 49 { 50 return gpiochip_get_data(irq_desc_get_handler_data(d)); 51 } 52 53 static inline u32 blzp1600_gpio_read(struct blzp1600_gpio *chip, unsigned int offset) 54 { 55 return readl_relaxed(chip->base + offset); 56 } 57 58 static inline void blzp1600_gpio_write(struct blzp1600_gpio *chip, unsigned int offset, u32 val) 59 { 60 writel_relaxed(val, chip->base + offset); 61 } 62 63 static inline void blzp1600_gpio_rmw(void __iomem *reg, u32 mask, bool set) 64 { 65 u32 val = readl_relaxed(reg); 66 67 if (set) 68 val |= mask; 69 else 70 val &= ~mask; 71 72 writel_relaxed(val, reg); 73 } 74 75 static void blzp1600_gpio_irq_mask(struct irq_data *d) 76 { 77 struct blzp1600_gpio *chip = get_blzp1600_gpio_from_irq_data(d); 78 79 guard(raw_spinlock_irqsave)(&chip->gc.bgpio_lock); 80 blzp1600_gpio_rmw(chip->base + GPIO_IM_REG, BIT(d->hwirq), 1); 81 } 82 83 static void blzp1600_gpio_irq_unmask(struct irq_data *d) 84 { 85 struct blzp1600_gpio *chip = get_blzp1600_gpio_from_irq_data(d); 86 87 guard(raw_spinlock_irqsave)(&chip->gc.bgpio_lock); 88 blzp1600_gpio_rmw(chip->base + GPIO_IM_REG, BIT(d->hwirq), 0); 89 } 90 91 static void blzp1600_gpio_irq_ack(struct irq_data *d) 92 { 93 struct blzp1600_gpio *chip = get_blzp1600_gpio_from_irq_data(d); 94 95 blzp1600_gpio_write(chip, GPIO_IC_REG, BIT(d->hwirq)); 96 } 97 98 static void blzp1600_gpio_irq_enable(struct irq_data *d) 99 { 100 struct blzp1600_gpio *chip = get_blzp1600_gpio_from_irq_data(d); 101 102 gpiochip_enable_irq(&chip->gc, irqd_to_hwirq(d)); 103 104 guard(raw_spinlock_irqsave)(&chip->gc.bgpio_lock); 105 blzp1600_gpio_rmw(chip->base + GPIO_DIR_REG, BIT(d->hwirq), 0); 106 blzp1600_gpio_rmw(chip->base + GPIO_IEN_REG, BIT(d->hwirq), 1); 107 } 108 109 static void blzp1600_gpio_irq_disable(struct irq_data *d) 110 { 111 struct blzp1600_gpio *chip = get_blzp1600_gpio_from_irq_data(d); 112 113 guard(raw_spinlock_irqsave)(&chip->gc.bgpio_lock); 114 blzp1600_gpio_rmw(chip->base + GPIO_IEN_REG, BIT(d->hwirq), 0); 115 gpiochip_disable_irq(&chip->gc, irqd_to_hwirq(d)); 116 } 117 118 static int blzp1600_gpio_irq_set_type(struct irq_data *d, u32 type) 119 { 120 struct blzp1600_gpio *chip = get_blzp1600_gpio_from_irq_data(d); 121 u32 edge_level, single_both, fall_rise; 122 int mask = BIT(d->hwirq); 123 124 guard(raw_spinlock_irqsave)(&chip->gc.bgpio_lock); 125 edge_level = blzp1600_gpio_read(chip, GPIO_IS_REG); 126 single_both = blzp1600_gpio_read(chip, GPIO_IBE_REG); 127 fall_rise = blzp1600_gpio_read(chip, GPIO_IEV_REG); 128 129 switch (type) { 130 case IRQ_TYPE_EDGE_BOTH: 131 edge_level &= ~mask; 132 single_both |= mask; 133 break; 134 case IRQ_TYPE_EDGE_RISING: 135 edge_level &= ~mask; 136 single_both &= ~mask; 137 fall_rise |= mask; 138 break; 139 case IRQ_TYPE_EDGE_FALLING: 140 edge_level &= ~mask; 141 single_both &= ~mask; 142 fall_rise &= ~mask; 143 break; 144 case IRQ_TYPE_LEVEL_HIGH: 145 edge_level |= mask; 146 fall_rise |= mask; 147 break; 148 case IRQ_TYPE_LEVEL_LOW: 149 edge_level |= mask; 150 fall_rise &= ~mask; 151 break; 152 default: 153 return -EINVAL; 154 } 155 156 blzp1600_gpio_write(chip, GPIO_IS_REG, edge_level); 157 blzp1600_gpio_write(chip, GPIO_IBE_REG, single_both); 158 blzp1600_gpio_write(chip, GPIO_IEV_REG, fall_rise); 159 160 if (type & IRQ_TYPE_LEVEL_MASK) 161 irq_set_handler_locked(d, handle_level_irq); 162 else 163 irq_set_handler_locked(d, handle_edge_irq); 164 165 return 0; 166 } 167 168 static const struct irq_chip blzp1600_gpio_irqchip = { 169 .name = DRIVER_NAME, 170 .irq_ack = blzp1600_gpio_irq_ack, 171 .irq_mask = blzp1600_gpio_irq_mask, 172 .irq_unmask = blzp1600_gpio_irq_unmask, 173 .irq_set_type = blzp1600_gpio_irq_set_type, 174 .irq_enable = blzp1600_gpio_irq_enable, 175 .irq_disable = blzp1600_gpio_irq_disable, 176 .flags = IRQCHIP_IMMUTABLE | IRQCHIP_MASK_ON_SUSPEND, 177 GPIOCHIP_IRQ_RESOURCE_HELPERS, 178 }; 179 180 static void blzp1600_gpio_irqhandler(struct irq_desc *desc) 181 { 182 struct blzp1600_gpio *gpio = get_blzp1600_gpio_from_irq_desc(desc); 183 struct irq_chip *irqchip = irq_desc_get_chip(desc); 184 unsigned long irq_status; 185 int hwirq = 0; 186 187 chained_irq_enter(irqchip, desc); 188 irq_status = blzp1600_gpio_read(gpio, GPIO_RIS_REG); 189 for_each_set_bit(hwirq, &irq_status, gpio->gc.ngpio) 190 generic_handle_domain_irq(gpio->gc.irq.domain, hwirq); 191 192 chained_irq_exit(irqchip, desc); 193 } 194 195 static int blzp1600_gpio_set_debounce(struct gpio_chip *gc, unsigned int offset, 196 unsigned int debounce) 197 { 198 struct blzp1600_gpio *chip = gpiochip_get_data(gc); 199 200 guard(raw_spinlock_irqsave)(&chip->gc.bgpio_lock); 201 blzp1600_gpio_rmw(chip->base + GPIO_DB_REG, BIT(offset), debounce); 202 203 return 0; 204 } 205 206 static int blzp1600_gpio_set_config(struct gpio_chip *gc, unsigned int offset, unsigned long config) 207 { 208 u32 debounce; 209 210 if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) 211 return -ENOTSUPP; 212 213 debounce = pinconf_to_config_argument(config); 214 return blzp1600_gpio_set_debounce(gc, offset, debounce); 215 } 216 217 static int blzp1600_gpio_probe(struct platform_device *pdev) 218 { 219 struct blzp1600_gpio *chip; 220 struct gpio_chip *gc; 221 int ret; 222 223 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); 224 if (!chip) 225 return -ENOMEM; 226 227 chip->base = devm_platform_ioremap_resource(pdev, 0); 228 if (IS_ERR(chip->base)) 229 return PTR_ERR(chip->base); 230 231 ret = bgpio_init(&chip->gc, &pdev->dev, 4, chip->base + GPIO_IDATA_REG, 232 chip->base + GPIO_SET_REG, chip->base + GPIO_CLR_REG, 233 chip->base + GPIO_DIR_REG, NULL, 0); 234 if (ret) 235 return dev_err_probe(&pdev->dev, ret, "Failed to register generic gpio\n"); 236 237 /* configure the gpio chip */ 238 gc = &chip->gc; 239 gc->set_config = blzp1600_gpio_set_config; 240 241 if (device_property_present(&pdev->dev, "interrupt-controller")) { 242 struct gpio_irq_chip *girq; 243 244 chip->irq = platform_get_irq(pdev, 0); 245 if (chip->irq < 0) 246 return chip->irq; 247 248 girq = &gc->irq; 249 gpio_irq_chip_set_chip(girq, &blzp1600_gpio_irqchip); 250 girq->parent_handler = blzp1600_gpio_irqhandler; 251 girq->num_parents = 1; 252 girq->parents = devm_kcalloc(&pdev->dev, 1, sizeof(*girq->parents), GFP_KERNEL); 253 if (!girq->parents) 254 return -ENOMEM; 255 256 girq->parents[0] = chip->irq; 257 girq->default_type = IRQ_TYPE_NONE; 258 } 259 260 return devm_gpiochip_add_data(&pdev->dev, gc, chip); 261 } 262 263 static const struct of_device_id blzp1600_gpio_of_match[] = { 264 { .compatible = "blaize,blzp1600-gpio", }, 265 { /* Sentinel */ }, 266 }; 267 MODULE_DEVICE_TABLE(of, blzp1600_gpio_of_match); 268 269 static struct platform_driver blzp1600_gpio_driver = { 270 .driver = { 271 .name = DRIVER_NAME, 272 .of_match_table = blzp1600_gpio_of_match, 273 }, 274 .probe = blzp1600_gpio_probe, 275 }; 276 277 module_platform_driver(blzp1600_gpio_driver); 278 279 MODULE_AUTHOR("Nikolaos Pasaloukos <nikolaos.pasaloukos@blaize.com>"); 280 MODULE_DESCRIPTION("Blaize BLZP1600 GPIO driver"); 281 MODULE_LICENSE("GPL"); 282