gpio-uniphier.c (13586B)
1// SPDX-License-Identifier: GPL-2.0 2// 3// Copyright (C) 2017 Socionext Inc. 4// Author: Masahiro Yamada <yamada.masahiro@socionext.com> 5 6#include <linux/bits.h> 7#include <linux/gpio/driver.h> 8#include <linux/irq.h> 9#include <linux/irqdomain.h> 10#include <linux/module.h> 11#include <linux/of.h> 12#include <linux/of_device.h> 13#include <linux/of_irq.h> 14#include <linux/platform_device.h> 15#include <linux/spinlock.h> 16#include <dt-bindings/gpio/uniphier-gpio.h> 17 18#define UNIPHIER_GPIO_IRQ_MAX_NUM 24 19 20#define UNIPHIER_GPIO_PORT_DATA 0x0 /* data */ 21#define UNIPHIER_GPIO_PORT_DIR 0x4 /* direction (1:in, 0:out) */ 22#define UNIPHIER_GPIO_IRQ_EN 0x90 /* irq enable */ 23#define UNIPHIER_GPIO_IRQ_MODE 0x94 /* irq mode (1: both edge) */ 24#define UNIPHIER_GPIO_IRQ_FLT_EN 0x98 /* noise filter enable */ 25#define UNIPHIER_GPIO_IRQ_FLT_CYC 0x9c /* noise filter clock cycle */ 26 27struct uniphier_gpio_priv { 28 struct gpio_chip chip; 29 struct irq_chip irq_chip; 30 struct irq_domain *domain; 31 void __iomem *regs; 32 spinlock_t lock; 33 u32 saved_vals[]; 34}; 35 36static unsigned int uniphier_gpio_bank_to_reg(unsigned int bank) 37{ 38 unsigned int reg; 39 40 reg = (bank + 1) * 8; 41 42 /* 43 * Unfortunately, the GPIO port registers are not contiguous because 44 * offset 0x90-0x9f is used for IRQ. Add 0x10 when crossing the region. 45 */ 46 if (reg >= UNIPHIER_GPIO_IRQ_EN) 47 reg += 0x10; 48 49 return reg; 50} 51 52static void uniphier_gpio_get_bank_and_mask(unsigned int offset, 53 unsigned int *bank, u32 *mask) 54{ 55 *bank = offset / UNIPHIER_GPIO_LINES_PER_BANK; 56 *mask = BIT(offset % UNIPHIER_GPIO_LINES_PER_BANK); 57} 58 59static void uniphier_gpio_reg_update(struct uniphier_gpio_priv *priv, 60 unsigned int reg, u32 mask, u32 val) 61{ 62 unsigned long flags; 63 u32 tmp; 64 65 spin_lock_irqsave(&priv->lock, flags); 66 tmp = readl(priv->regs + reg); 67 tmp &= ~mask; 68 tmp |= mask & val; 69 writel(tmp, priv->regs + reg); 70 spin_unlock_irqrestore(&priv->lock, flags); 71} 72 73static void uniphier_gpio_bank_write(struct gpio_chip *chip, unsigned int bank, 74 unsigned int reg, u32 mask, u32 val) 75{ 76 struct uniphier_gpio_priv *priv = gpiochip_get_data(chip); 77 78 if (!mask) 79 return; 80 81 uniphier_gpio_reg_update(priv, uniphier_gpio_bank_to_reg(bank) + reg, 82 mask, val); 83} 84 85static void uniphier_gpio_offset_write(struct gpio_chip *chip, 86 unsigned int offset, unsigned int reg, 87 int val) 88{ 89 unsigned int bank; 90 u32 mask; 91 92 uniphier_gpio_get_bank_and_mask(offset, &bank, &mask); 93 94 uniphier_gpio_bank_write(chip, bank, reg, mask, val ? mask : 0); 95} 96 97static int uniphier_gpio_offset_read(struct gpio_chip *chip, 98 unsigned int offset, unsigned int reg) 99{ 100 struct uniphier_gpio_priv *priv = gpiochip_get_data(chip); 101 unsigned int bank, reg_offset; 102 u32 mask; 103 104 uniphier_gpio_get_bank_and_mask(offset, &bank, &mask); 105 reg_offset = uniphier_gpio_bank_to_reg(bank) + reg; 106 107 return !!(readl(priv->regs + reg_offset) & mask); 108} 109 110static int uniphier_gpio_get_direction(struct gpio_chip *chip, 111 unsigned int offset) 112{ 113 if (uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_PORT_DIR)) 114 return GPIO_LINE_DIRECTION_IN; 115 116 return GPIO_LINE_DIRECTION_OUT; 117} 118 119static int uniphier_gpio_direction_input(struct gpio_chip *chip, 120 unsigned int offset) 121{ 122 uniphier_gpio_offset_write(chip, offset, UNIPHIER_GPIO_PORT_DIR, 1); 123 124 return 0; 125} 126 127static int uniphier_gpio_direction_output(struct gpio_chip *chip, 128 unsigned int offset, int val) 129{ 130 uniphier_gpio_offset_write(chip, offset, UNIPHIER_GPIO_PORT_DATA, val); 131 uniphier_gpio_offset_write(chip, offset, UNIPHIER_GPIO_PORT_DIR, 0); 132 133 return 0; 134} 135 136static int uniphier_gpio_get(struct gpio_chip *chip, unsigned int offset) 137{ 138 return uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_PORT_DATA); 139} 140 141static void uniphier_gpio_set(struct gpio_chip *chip, 142 unsigned int offset, int val) 143{ 144 uniphier_gpio_offset_write(chip, offset, UNIPHIER_GPIO_PORT_DATA, val); 145} 146 147static void uniphier_gpio_set_multiple(struct gpio_chip *chip, 148 unsigned long *mask, unsigned long *bits) 149{ 150 unsigned long i, bank, bank_mask, bank_bits; 151 152 for_each_set_clump8(i, bank_mask, mask, chip->ngpio) { 153 bank = i / UNIPHIER_GPIO_LINES_PER_BANK; 154 bank_bits = bitmap_get_value8(bits, i); 155 156 uniphier_gpio_bank_write(chip, bank, UNIPHIER_GPIO_PORT_DATA, 157 bank_mask, bank_bits); 158 } 159} 160 161static int uniphier_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) 162{ 163 struct irq_fwspec fwspec; 164 165 if (offset < UNIPHIER_GPIO_IRQ_OFFSET) 166 return -ENXIO; 167 168 fwspec.fwnode = of_node_to_fwnode(chip->parent->of_node); 169 fwspec.param_count = 2; 170 fwspec.param[0] = offset - UNIPHIER_GPIO_IRQ_OFFSET; 171 /* 172 * IRQ_TYPE_NONE is rejected by the parent irq domain. Set LEVEL_HIGH 173 * temporarily. Anyway, ->irq_set_type() will override it later. 174 */ 175 fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH; 176 177 return irq_create_fwspec_mapping(&fwspec); 178} 179 180static void uniphier_gpio_irq_mask(struct irq_data *data) 181{ 182 struct uniphier_gpio_priv *priv = irq_data_get_irq_chip_data(data); 183 u32 mask = BIT(irqd_to_hwirq(data)); 184 185 uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, 0); 186 187 irq_chip_mask_parent(data); 188} 189 190static void uniphier_gpio_irq_unmask(struct irq_data *data) 191{ 192 struct uniphier_gpio_priv *priv = irq_data_get_irq_chip_data(data); 193 u32 mask = BIT(irqd_to_hwirq(data)); 194 195 uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_EN, mask, mask); 196 197 irq_chip_unmask_parent(data); 198} 199 200static int uniphier_gpio_irq_set_type(struct irq_data *data, unsigned int type) 201{ 202 struct uniphier_gpio_priv *priv = irq_data_get_irq_chip_data(data); 203 u32 mask = BIT(irqd_to_hwirq(data)); 204 u32 val = 0; 205 206 if (type == IRQ_TYPE_EDGE_BOTH) { 207 val = mask; 208 type = IRQ_TYPE_EDGE_FALLING; 209 } 210 211 uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_MODE, mask, val); 212 /* To enable both edge detection, the noise filter must be enabled. */ 213 uniphier_gpio_reg_update(priv, UNIPHIER_GPIO_IRQ_FLT_EN, mask, val); 214 215 return irq_chip_set_type_parent(data, type); 216} 217 218static int uniphier_gpio_irq_get_parent_hwirq(struct uniphier_gpio_priv *priv, 219 unsigned int hwirq) 220{ 221 struct device_node *np = priv->chip.parent->of_node; 222 const __be32 *range; 223 u32 base, parent_base, size; 224 int len; 225 226 range = of_get_property(np, "socionext,interrupt-ranges", &len); 227 if (!range) 228 return -EINVAL; 229 230 len /= sizeof(*range); 231 232 for (; len >= 3; len -= 3) { 233 base = be32_to_cpu(*range++); 234 parent_base = be32_to_cpu(*range++); 235 size = be32_to_cpu(*range++); 236 237 if (base <= hwirq && hwirq < base + size) 238 return hwirq - base + parent_base; 239 } 240 241 return -ENOENT; 242} 243 244static int uniphier_gpio_irq_domain_translate(struct irq_domain *domain, 245 struct irq_fwspec *fwspec, 246 unsigned long *out_hwirq, 247 unsigned int *out_type) 248{ 249 if (WARN_ON(fwspec->param_count < 2)) 250 return -EINVAL; 251 252 *out_hwirq = fwspec->param[0]; 253 *out_type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; 254 255 return 0; 256} 257 258static int uniphier_gpio_irq_domain_alloc(struct irq_domain *domain, 259 unsigned int virq, 260 unsigned int nr_irqs, void *arg) 261{ 262 struct uniphier_gpio_priv *priv = domain->host_data; 263 struct irq_fwspec parent_fwspec; 264 irq_hw_number_t hwirq; 265 unsigned int type; 266 int ret; 267 268 if (WARN_ON(nr_irqs != 1)) 269 return -EINVAL; 270 271 ret = uniphier_gpio_irq_domain_translate(domain, arg, &hwirq, &type); 272 if (ret) 273 return ret; 274 275 ret = uniphier_gpio_irq_get_parent_hwirq(priv, hwirq); 276 if (ret < 0) 277 return ret; 278 279 /* parent is UniPhier AIDET */ 280 parent_fwspec.fwnode = domain->parent->fwnode; 281 parent_fwspec.param_count = 2; 282 parent_fwspec.param[0] = ret; 283 parent_fwspec.param[1] = (type == IRQ_TYPE_EDGE_BOTH) ? 284 IRQ_TYPE_EDGE_FALLING : type; 285 286 ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, 287 &priv->irq_chip, priv); 288 if (ret) 289 return ret; 290 291 return irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec); 292} 293 294static int uniphier_gpio_irq_domain_activate(struct irq_domain *domain, 295 struct irq_data *data, bool early) 296{ 297 struct uniphier_gpio_priv *priv = domain->host_data; 298 struct gpio_chip *chip = &priv->chip; 299 300 return gpiochip_lock_as_irq(chip, 301 irqd_to_hwirq(data) + UNIPHIER_GPIO_IRQ_OFFSET); 302} 303 304static void uniphier_gpio_irq_domain_deactivate(struct irq_domain *domain, 305 struct irq_data *data) 306{ 307 struct uniphier_gpio_priv *priv = domain->host_data; 308 struct gpio_chip *chip = &priv->chip; 309 310 gpiochip_unlock_as_irq(chip, 311 irqd_to_hwirq(data) + UNIPHIER_GPIO_IRQ_OFFSET); 312} 313 314static const struct irq_domain_ops uniphier_gpio_irq_domain_ops = { 315 .alloc = uniphier_gpio_irq_domain_alloc, 316 .free = irq_domain_free_irqs_common, 317 .activate = uniphier_gpio_irq_domain_activate, 318 .deactivate = uniphier_gpio_irq_domain_deactivate, 319 .translate = uniphier_gpio_irq_domain_translate, 320}; 321 322static void uniphier_gpio_hw_init(struct uniphier_gpio_priv *priv) 323{ 324 /* 325 * Due to the hardware design, the noise filter must be enabled to 326 * detect both edge interrupts. This filter is intended to remove the 327 * noise from the irq lines. It does not work for GPIO input, so GPIO 328 * debounce is not supported. Unfortunately, the filter period is 329 * shared among all irq lines. Just choose a sensible period here. 330 */ 331 writel(0xff, priv->regs + UNIPHIER_GPIO_IRQ_FLT_CYC); 332} 333 334static unsigned int uniphier_gpio_get_nbanks(unsigned int ngpio) 335{ 336 return DIV_ROUND_UP(ngpio, UNIPHIER_GPIO_LINES_PER_BANK); 337} 338 339static int uniphier_gpio_probe(struct platform_device *pdev) 340{ 341 struct device *dev = &pdev->dev; 342 struct device_node *parent_np; 343 struct irq_domain *parent_domain; 344 struct uniphier_gpio_priv *priv; 345 struct gpio_chip *chip; 346 struct irq_chip *irq_chip; 347 unsigned int nregs; 348 u32 ngpios; 349 int ret; 350 351 parent_np = of_irq_find_parent(dev->of_node); 352 if (!parent_np) 353 return -ENXIO; 354 355 parent_domain = irq_find_host(parent_np); 356 of_node_put(parent_np); 357 if (!parent_domain) 358 return -EPROBE_DEFER; 359 360 ret = of_property_read_u32(dev->of_node, "ngpios", &ngpios); 361 if (ret) 362 return ret; 363 364 nregs = uniphier_gpio_get_nbanks(ngpios) * 2 + 3; 365 priv = devm_kzalloc(dev, struct_size(priv, saved_vals, nregs), 366 GFP_KERNEL); 367 if (!priv) 368 return -ENOMEM; 369 370 priv->regs = devm_platform_ioremap_resource(pdev, 0); 371 if (IS_ERR(priv->regs)) 372 return PTR_ERR(priv->regs); 373 374 spin_lock_init(&priv->lock); 375 376 chip = &priv->chip; 377 chip->label = dev_name(dev); 378 chip->parent = dev; 379 chip->request = gpiochip_generic_request; 380 chip->free = gpiochip_generic_free; 381 chip->get_direction = uniphier_gpio_get_direction; 382 chip->direction_input = uniphier_gpio_direction_input; 383 chip->direction_output = uniphier_gpio_direction_output; 384 chip->get = uniphier_gpio_get; 385 chip->set = uniphier_gpio_set; 386 chip->set_multiple = uniphier_gpio_set_multiple; 387 chip->to_irq = uniphier_gpio_to_irq; 388 chip->base = -1; 389 chip->ngpio = ngpios; 390 391 irq_chip = &priv->irq_chip; 392 irq_chip->name = dev_name(dev); 393 irq_chip->irq_mask = uniphier_gpio_irq_mask; 394 irq_chip->irq_unmask = uniphier_gpio_irq_unmask; 395 irq_chip->irq_eoi = irq_chip_eoi_parent; 396 irq_chip->irq_set_affinity = irq_chip_set_affinity_parent; 397 irq_chip->irq_set_type = uniphier_gpio_irq_set_type; 398 399 uniphier_gpio_hw_init(priv); 400 401 ret = devm_gpiochip_add_data(dev, chip, priv); 402 if (ret) 403 return ret; 404 405 priv->domain = irq_domain_create_hierarchy( 406 parent_domain, 0, 407 UNIPHIER_GPIO_IRQ_MAX_NUM, 408 of_node_to_fwnode(dev->of_node), 409 &uniphier_gpio_irq_domain_ops, priv); 410 if (!priv->domain) 411 return -ENOMEM; 412 413 platform_set_drvdata(pdev, priv); 414 415 return 0; 416} 417 418static int uniphier_gpio_remove(struct platform_device *pdev) 419{ 420 struct uniphier_gpio_priv *priv = platform_get_drvdata(pdev); 421 422 irq_domain_remove(priv->domain); 423 424 return 0; 425} 426 427static int __maybe_unused uniphier_gpio_suspend(struct device *dev) 428{ 429 struct uniphier_gpio_priv *priv = dev_get_drvdata(dev); 430 unsigned int nbanks = uniphier_gpio_get_nbanks(priv->chip.ngpio); 431 u32 *val = priv->saved_vals; 432 unsigned int reg; 433 int i; 434 435 for (i = 0; i < nbanks; i++) { 436 reg = uniphier_gpio_bank_to_reg(i); 437 438 *val++ = readl(priv->regs + reg + UNIPHIER_GPIO_PORT_DATA); 439 *val++ = readl(priv->regs + reg + UNIPHIER_GPIO_PORT_DIR); 440 } 441 442 *val++ = readl(priv->regs + UNIPHIER_GPIO_IRQ_EN); 443 *val++ = readl(priv->regs + UNIPHIER_GPIO_IRQ_MODE); 444 *val++ = readl(priv->regs + UNIPHIER_GPIO_IRQ_FLT_EN); 445 446 return 0; 447} 448 449static int __maybe_unused uniphier_gpio_resume(struct device *dev) 450{ 451 struct uniphier_gpio_priv *priv = dev_get_drvdata(dev); 452 unsigned int nbanks = uniphier_gpio_get_nbanks(priv->chip.ngpio); 453 const u32 *val = priv->saved_vals; 454 unsigned int reg; 455 int i; 456 457 for (i = 0; i < nbanks; i++) { 458 reg = uniphier_gpio_bank_to_reg(i); 459 460 writel(*val++, priv->regs + reg + UNIPHIER_GPIO_PORT_DATA); 461 writel(*val++, priv->regs + reg + UNIPHIER_GPIO_PORT_DIR); 462 } 463 464 writel(*val++, priv->regs + UNIPHIER_GPIO_IRQ_EN); 465 writel(*val++, priv->regs + UNIPHIER_GPIO_IRQ_MODE); 466 writel(*val++, priv->regs + UNIPHIER_GPIO_IRQ_FLT_EN); 467 468 uniphier_gpio_hw_init(priv); 469 470 return 0; 471} 472 473static const struct dev_pm_ops uniphier_gpio_pm_ops = { 474 SET_LATE_SYSTEM_SLEEP_PM_OPS(uniphier_gpio_suspend, 475 uniphier_gpio_resume) 476}; 477 478static const struct of_device_id uniphier_gpio_match[] = { 479 { .compatible = "socionext,uniphier-gpio" }, 480 { /* sentinel */ } 481}; 482MODULE_DEVICE_TABLE(of, uniphier_gpio_match); 483 484static struct platform_driver uniphier_gpio_driver = { 485 .probe = uniphier_gpio_probe, 486 .remove = uniphier_gpio_remove, 487 .driver = { 488 .name = "uniphier-gpio", 489 .of_match_table = uniphier_gpio_match, 490 .pm = &uniphier_gpio_pm_ops, 491 }, 492}; 493module_platform_driver(uniphier_gpio_driver); 494 495MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>"); 496MODULE_DESCRIPTION("UniPhier GPIO driver"); 497MODULE_LICENSE("GPL v2");