Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.17-rc2 281 lines 7.6 kB view raw
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 37struct blzp1600_gpio { 38 void __iomem *base; 39 struct gpio_chip gc; 40 int irq; 41}; 42 43static 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 48static 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 53static inline u32 blzp1600_gpio_read(struct blzp1600_gpio *chip, unsigned int offset) 54{ 55 return readl_relaxed(chip->base + offset); 56} 57 58static inline void blzp1600_gpio_write(struct blzp1600_gpio *chip, unsigned int offset, u32 val) 59{ 60 writel_relaxed(val, chip->base + offset); 61} 62 63static 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 75static 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 83static 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 91static 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 98static 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 109static 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 118static 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 168static 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 180static 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 195static 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 206static 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 217static 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 263static const struct of_device_id blzp1600_gpio_of_match[] = { 264 { .compatible = "blaize,blzp1600-gpio", }, 265 { /* Sentinel */ }, 266}; 267MODULE_DEVICE_TABLE(of, blzp1600_gpio_of_match); 268 269static 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 277module_platform_driver(blzp1600_gpio_driver); 278 279MODULE_AUTHOR("Nikolaos Pasaloukos <nikolaos.pasaloukos@blaize.com>"); 280MODULE_DESCRIPTION("Blaize BLZP1600 GPIO driver"); 281MODULE_LICENSE("GPL");