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 v4.14-rc7 474 lines 11 kB view raw
1#include <linux/kernel.h> 2#include <linux/init.h> 3#include <linux/gpio/driver.h> 4#include <linux/of_gpio.h> 5#include <linux/io.h> 6#include <linux/interrupt.h> 7#include <linux/platform_device.h> 8 9#define ETRAX_FS_rw_pa_dout 0 10#define ETRAX_FS_r_pa_din 4 11#define ETRAX_FS_rw_pa_oe 8 12#define ETRAX_FS_rw_intr_cfg 12 13#define ETRAX_FS_rw_intr_mask 16 14#define ETRAX_FS_rw_ack_intr 20 15#define ETRAX_FS_r_intr 24 16#define ETRAX_FS_r_masked_intr 28 17#define ETRAX_FS_rw_pb_dout 32 18#define ETRAX_FS_r_pb_din 36 19#define ETRAX_FS_rw_pb_oe 40 20#define ETRAX_FS_rw_pc_dout 48 21#define ETRAX_FS_r_pc_din 52 22#define ETRAX_FS_rw_pc_oe 56 23#define ETRAX_FS_rw_pd_dout 64 24#define ETRAX_FS_r_pd_din 68 25#define ETRAX_FS_rw_pd_oe 72 26#define ETRAX_FS_rw_pe_dout 80 27#define ETRAX_FS_r_pe_din 84 28#define ETRAX_FS_rw_pe_oe 88 29 30#define ARTPEC3_r_pa_din 0 31#define ARTPEC3_rw_pa_dout 4 32#define ARTPEC3_rw_pa_oe 8 33#define ARTPEC3_r_pb_din 44 34#define ARTPEC3_rw_pb_dout 48 35#define ARTPEC3_rw_pb_oe 52 36#define ARTPEC3_r_pc_din 88 37#define ARTPEC3_rw_pc_dout 92 38#define ARTPEC3_rw_pc_oe 96 39#define ARTPEC3_r_pd_din 116 40#define ARTPEC3_rw_intr_cfg 120 41#define ARTPEC3_rw_intr_pins 124 42#define ARTPEC3_rw_intr_mask 128 43#define ARTPEC3_rw_ack_intr 132 44#define ARTPEC3_r_masked_intr 140 45 46#define GIO_CFG_OFF 0 47#define GIO_CFG_HI 1 48#define GIO_CFG_LO 2 49#define GIO_CFG_SET 3 50#define GIO_CFG_POSEDGE 5 51#define GIO_CFG_NEGEDGE 6 52#define GIO_CFG_ANYEDGE 7 53 54struct etraxfs_gpio_info; 55 56struct etraxfs_gpio_block { 57 raw_spinlock_t lock; 58 u32 mask; 59 u32 cfg; 60 u32 pins; 61 unsigned int group[8]; 62 63 void __iomem *regs; 64 const struct etraxfs_gpio_info *info; 65}; 66 67struct etraxfs_gpio_chip { 68 struct gpio_chip gc; 69 struct etraxfs_gpio_block *block; 70}; 71 72struct etraxfs_gpio_port { 73 const char *label; 74 unsigned int oe; 75 unsigned int dout; 76 unsigned int din; 77 unsigned int ngpio; 78}; 79 80struct etraxfs_gpio_info { 81 unsigned int num_ports; 82 const struct etraxfs_gpio_port *ports; 83 84 unsigned int rw_ack_intr; 85 unsigned int rw_intr_mask; 86 unsigned int rw_intr_cfg; 87 unsigned int rw_intr_pins; 88 unsigned int r_masked_intr; 89}; 90 91static const struct etraxfs_gpio_port etraxfs_gpio_etraxfs_ports[] = { 92 { 93 .label = "A", 94 .ngpio = 8, 95 .oe = ETRAX_FS_rw_pa_oe, 96 .dout = ETRAX_FS_rw_pa_dout, 97 .din = ETRAX_FS_r_pa_din, 98 }, 99 { 100 .label = "B", 101 .ngpio = 18, 102 .oe = ETRAX_FS_rw_pb_oe, 103 .dout = ETRAX_FS_rw_pb_dout, 104 .din = ETRAX_FS_r_pb_din, 105 }, 106 { 107 .label = "C", 108 .ngpio = 18, 109 .oe = ETRAX_FS_rw_pc_oe, 110 .dout = ETRAX_FS_rw_pc_dout, 111 .din = ETRAX_FS_r_pc_din, 112 }, 113 { 114 .label = "D", 115 .ngpio = 18, 116 .oe = ETRAX_FS_rw_pd_oe, 117 .dout = ETRAX_FS_rw_pd_dout, 118 .din = ETRAX_FS_r_pd_din, 119 }, 120 { 121 .label = "E", 122 .ngpio = 18, 123 .oe = ETRAX_FS_rw_pe_oe, 124 .dout = ETRAX_FS_rw_pe_dout, 125 .din = ETRAX_FS_r_pe_din, 126 }, 127}; 128 129static const struct etraxfs_gpio_info etraxfs_gpio_etraxfs = { 130 .num_ports = ARRAY_SIZE(etraxfs_gpio_etraxfs_ports), 131 .ports = etraxfs_gpio_etraxfs_ports, 132 .rw_ack_intr = ETRAX_FS_rw_ack_intr, 133 .rw_intr_mask = ETRAX_FS_rw_intr_mask, 134 .rw_intr_cfg = ETRAX_FS_rw_intr_cfg, 135 .r_masked_intr = ETRAX_FS_r_masked_intr, 136}; 137 138static const struct etraxfs_gpio_port etraxfs_gpio_artpec3_ports[] = { 139 { 140 .label = "A", 141 .ngpio = 32, 142 .oe = ARTPEC3_rw_pa_oe, 143 .dout = ARTPEC3_rw_pa_dout, 144 .din = ARTPEC3_r_pa_din, 145 }, 146 { 147 .label = "B", 148 .ngpio = 32, 149 .oe = ARTPEC3_rw_pb_oe, 150 .dout = ARTPEC3_rw_pb_dout, 151 .din = ARTPEC3_r_pb_din, 152 }, 153 { 154 .label = "C", 155 .ngpio = 16, 156 .oe = ARTPEC3_rw_pc_oe, 157 .dout = ARTPEC3_rw_pc_dout, 158 .din = ARTPEC3_r_pc_din, 159 }, 160 { 161 .label = "D", 162 .ngpio = 32, 163 .din = ARTPEC3_r_pd_din, 164 }, 165}; 166 167static const struct etraxfs_gpio_info etraxfs_gpio_artpec3 = { 168 .num_ports = ARRAY_SIZE(etraxfs_gpio_artpec3_ports), 169 .ports = etraxfs_gpio_artpec3_ports, 170 .rw_ack_intr = ARTPEC3_rw_ack_intr, 171 .rw_intr_mask = ARTPEC3_rw_intr_mask, 172 .rw_intr_cfg = ARTPEC3_rw_intr_cfg, 173 .r_masked_intr = ARTPEC3_r_masked_intr, 174 .rw_intr_pins = ARTPEC3_rw_intr_pins, 175}; 176 177static unsigned int etraxfs_gpio_chip_to_port(struct gpio_chip *gc) 178{ 179 return gc->label[0] - 'A'; 180} 181 182static int etraxfs_gpio_of_xlate(struct gpio_chip *gc, 183 const struct of_phandle_args *gpiospec, 184 u32 *flags) 185{ 186 /* 187 * Port numbers are A to E, and the properties are integers, so we 188 * specify them as 0xA - 0xE. 189 */ 190 if (etraxfs_gpio_chip_to_port(gc) + 0xA != gpiospec->args[2]) 191 return -EINVAL; 192 193 return of_gpio_simple_xlate(gc, gpiospec, flags); 194} 195 196static const struct of_device_id etraxfs_gpio_of_table[] = { 197 { 198 .compatible = "axis,etraxfs-gio", 199 .data = &etraxfs_gpio_etraxfs, 200 }, 201 { 202 .compatible = "axis,artpec3-gio", 203 .data = &etraxfs_gpio_artpec3, 204 }, 205 {}, 206}; 207 208static unsigned int etraxfs_gpio_to_group_irq(unsigned int gpio) 209{ 210 return gpio % 8; 211} 212 213static unsigned int etraxfs_gpio_to_group_pin(struct etraxfs_gpio_chip *chip, 214 unsigned int gpio) 215{ 216 return 4 * etraxfs_gpio_chip_to_port(&chip->gc) + gpio / 8; 217} 218 219static void etraxfs_gpio_irq_ack(struct irq_data *d) 220{ 221 struct etraxfs_gpio_chip *chip = 222 gpiochip_get_data(irq_data_get_irq_chip_data(d)); 223 struct etraxfs_gpio_block *block = chip->block; 224 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); 225 226 writel(BIT(grpirq), block->regs + block->info->rw_ack_intr); 227} 228 229static void etraxfs_gpio_irq_mask(struct irq_data *d) 230{ 231 struct etraxfs_gpio_chip *chip = 232 gpiochip_get_data(irq_data_get_irq_chip_data(d)); 233 struct etraxfs_gpio_block *block = chip->block; 234 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); 235 236 raw_spin_lock(&block->lock); 237 block->mask &= ~BIT(grpirq); 238 writel(block->mask, block->regs + block->info->rw_intr_mask); 239 raw_spin_unlock(&block->lock); 240} 241 242static void etraxfs_gpio_irq_unmask(struct irq_data *d) 243{ 244 struct etraxfs_gpio_chip *chip = 245 gpiochip_get_data(irq_data_get_irq_chip_data(d)); 246 struct etraxfs_gpio_block *block = chip->block; 247 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); 248 249 raw_spin_lock(&block->lock); 250 block->mask |= BIT(grpirq); 251 writel(block->mask, block->regs + block->info->rw_intr_mask); 252 raw_spin_unlock(&block->lock); 253} 254 255static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type) 256{ 257 struct etraxfs_gpio_chip *chip = 258 gpiochip_get_data(irq_data_get_irq_chip_data(d)); 259 struct etraxfs_gpio_block *block = chip->block; 260 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); 261 u32 cfg; 262 263 switch (type) { 264 case IRQ_TYPE_EDGE_RISING: 265 cfg = GIO_CFG_POSEDGE; 266 break; 267 case IRQ_TYPE_EDGE_FALLING: 268 cfg = GIO_CFG_NEGEDGE; 269 break; 270 case IRQ_TYPE_EDGE_BOTH: 271 cfg = GIO_CFG_ANYEDGE; 272 break; 273 case IRQ_TYPE_LEVEL_LOW: 274 cfg = GIO_CFG_LO; 275 break; 276 case IRQ_TYPE_LEVEL_HIGH: 277 cfg = GIO_CFG_HI; 278 break; 279 default: 280 return -EINVAL; 281 } 282 283 raw_spin_lock(&block->lock); 284 block->cfg &= ~(0x7 << (grpirq * 3)); 285 block->cfg |= (cfg << (grpirq * 3)); 286 writel(block->cfg, block->regs + block->info->rw_intr_cfg); 287 raw_spin_unlock(&block->lock); 288 289 return 0; 290} 291 292static int etraxfs_gpio_irq_request_resources(struct irq_data *d) 293{ 294 struct etraxfs_gpio_chip *chip = 295 gpiochip_get_data(irq_data_get_irq_chip_data(d)); 296 struct etraxfs_gpio_block *block = chip->block; 297 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); 298 int ret = -EBUSY; 299 300 raw_spin_lock(&block->lock); 301 if (block->group[grpirq]) 302 goto out; 303 304 ret = gpiochip_lock_as_irq(&chip->gc, d->hwirq); 305 if (ret) 306 goto out; 307 308 block->group[grpirq] = d->irq; 309 if (block->info->rw_intr_pins) { 310 unsigned int pin = etraxfs_gpio_to_group_pin(chip, d->hwirq); 311 312 block->pins &= ~(0xf << (grpirq * 4)); 313 block->pins |= (pin << (grpirq * 4)); 314 315 writel(block->pins, block->regs + block->info->rw_intr_pins); 316 } 317 318out: 319 raw_spin_unlock(&block->lock); 320 return ret; 321} 322 323static void etraxfs_gpio_irq_release_resources(struct irq_data *d) 324{ 325 struct etraxfs_gpio_chip *chip = 326 gpiochip_get_data(irq_data_get_irq_chip_data(d)); 327 struct etraxfs_gpio_block *block = chip->block; 328 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); 329 330 raw_spin_lock(&block->lock); 331 block->group[grpirq] = 0; 332 gpiochip_unlock_as_irq(&chip->gc, d->hwirq); 333 raw_spin_unlock(&block->lock); 334} 335 336static struct irq_chip etraxfs_gpio_irq_chip = { 337 .name = "gpio-etraxfs", 338 .irq_ack = etraxfs_gpio_irq_ack, 339 .irq_mask = etraxfs_gpio_irq_mask, 340 .irq_unmask = etraxfs_gpio_irq_unmask, 341 .irq_set_type = etraxfs_gpio_irq_set_type, 342 .irq_request_resources = etraxfs_gpio_irq_request_resources, 343 .irq_release_resources = etraxfs_gpio_irq_release_resources, 344}; 345 346static irqreturn_t etraxfs_gpio_interrupt(int irq, void *dev_id) 347{ 348 struct etraxfs_gpio_block *block = dev_id; 349 unsigned long intr = readl(block->regs + block->info->r_masked_intr); 350 int bit; 351 352 for_each_set_bit(bit, &intr, 8) 353 generic_handle_irq(block->group[bit]); 354 355 return IRQ_RETVAL(intr & 0xff); 356} 357 358static int etraxfs_gpio_probe(struct platform_device *pdev) 359{ 360 struct device *dev = &pdev->dev; 361 const struct etraxfs_gpio_info *info; 362 const struct of_device_id *match; 363 struct etraxfs_gpio_block *block; 364 struct etraxfs_gpio_chip *chips; 365 struct resource *res, *irq; 366 bool allportsirq = false; 367 void __iomem *regs; 368 int ret; 369 int i; 370 371 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 372 regs = devm_ioremap_resource(dev, res); 373 if (IS_ERR(regs)) 374 return PTR_ERR(regs); 375 376 match = of_match_node(etraxfs_gpio_of_table, dev->of_node); 377 if (!match) 378 return -EINVAL; 379 380 info = match->data; 381 382 chips = devm_kzalloc(dev, sizeof(*chips) * info->num_ports, GFP_KERNEL); 383 if (!chips) 384 return -ENOMEM; 385 386 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 387 if (!irq) 388 return -EINVAL; 389 390 block = devm_kzalloc(dev, sizeof(*block), GFP_KERNEL); 391 if (!block) 392 return -ENOMEM; 393 394 raw_spin_lock_init(&block->lock); 395 396 block->regs = regs; 397 block->info = info; 398 399 writel(0, block->regs + info->rw_intr_mask); 400 writel(0, block->regs + info->rw_intr_cfg); 401 if (info->rw_intr_pins) { 402 allportsirq = true; 403 writel(0, block->regs + info->rw_intr_pins); 404 } 405 406 ret = devm_request_irq(dev, irq->start, etraxfs_gpio_interrupt, 407 IRQF_SHARED, dev_name(dev), block); 408 if (ret) { 409 dev_err(dev, "Unable to request irq %d\n", ret); 410 return ret; 411 } 412 413 for (i = 0; i < info->num_ports; i++) { 414 struct etraxfs_gpio_chip *chip = &chips[i]; 415 struct gpio_chip *gc = &chip->gc; 416 const struct etraxfs_gpio_port *port = &info->ports[i]; 417 unsigned long flags = BGPIOF_READ_OUTPUT_REG_SET; 418 void __iomem *dat = regs + port->din; 419 void __iomem *set = regs + port->dout; 420 void __iomem *dirout = regs + port->oe; 421 422 chip->block = block; 423 424 if (dirout == set) { 425 dirout = set = NULL; 426 flags = BGPIOF_NO_OUTPUT; 427 } 428 429 ret = bgpio_init(gc, dev, 4, 430 dat, set, NULL, dirout, NULL, 431 flags); 432 if (ret) { 433 dev_err(dev, "Unable to init port %s\n", 434 port->label); 435 continue; 436 } 437 438 gc->ngpio = port->ngpio; 439 gc->label = port->label; 440 441 gc->of_node = dev->of_node; 442 gc->of_gpio_n_cells = 3; 443 gc->of_xlate = etraxfs_gpio_of_xlate; 444 445 ret = gpiochip_add_data(gc, chip); 446 if (ret) { 447 dev_err(dev, "Unable to register port %s\n", 448 gc->label); 449 continue; 450 } 451 452 if (i > 0 && !allportsirq) 453 continue; 454 455 ret = gpiochip_irqchip_add(gc, &etraxfs_gpio_irq_chip, 0, 456 handle_level_irq, IRQ_TYPE_NONE); 457 if (ret) { 458 dev_err(dev, "Unable to add irqchip to port %s\n", 459 gc->label); 460 } 461 } 462 463 return 0; 464} 465 466static struct platform_driver etraxfs_gpio_driver = { 467 .driver = { 468 .name = "etraxfs-gpio", 469 .of_match_table = of_match_ptr(etraxfs_gpio_of_table), 470 }, 471 .probe = etraxfs_gpio_probe, 472}; 473 474builtin_platform_driver(etraxfs_gpio_driver);