1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * arch/sh/boards/mach-x3proto/gpio.c 4 * 5 * Renesas SH-X3 Prototype Baseboard GPIO Support. 6 * 7 * Copyright (C) 2010 - 2012 Paul Mundt 8 */ 9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 11 #include <linux/init.h> 12 #include <linux/interrupt.h> 13 #include <linux/gpio/driver.h> 14 #include <linux/irq.h> 15 #include <linux/kernel.h> 16 #include <linux/spinlock.h> 17 #include <linux/irqdomain.h> 18 #include <linux/io.h> 19 #include <mach/ilsel.h> 20 #include <mach/hardware.h> 21 22 #define KEYCTLR 0xb81c0000 23 #define KEYOUTR 0xb81c0002 24 #define KEYDETR 0xb81c0004 25 26 static DEFINE_SPINLOCK(x3proto_gpio_lock); 27 static struct irq_domain *x3proto_irq_domain; 28 29 static int x3proto_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) 30 { 31 unsigned long flags; 32 unsigned int data; 33 34 spin_lock_irqsave(&x3proto_gpio_lock, flags); 35 data = __raw_readw(KEYCTLR); 36 data |= (1 << gpio); 37 __raw_writew(data, KEYCTLR); 38 spin_unlock_irqrestore(&x3proto_gpio_lock, flags); 39 40 return 0; 41 } 42 43 static int x3proto_gpio_get(struct gpio_chip *chip, unsigned gpio) 44 { 45 return !!(__raw_readw(KEYDETR) & (1 << gpio)); 46 } 47 48 static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) 49 { 50 int virq; 51 52 if (gpio < chip->ngpio) 53 virq = irq_create_mapping(x3proto_irq_domain, gpio); 54 else 55 virq = -ENXIO; 56 57 return virq; 58 } 59 60 static void x3proto_gpio_irq_handler(struct irq_desc *desc) 61 { 62 struct irq_data *data = irq_desc_get_irq_data(desc); 63 struct irq_chip *chip = irq_data_get_irq_chip(data); 64 unsigned long mask; 65 int pin; 66 67 chip->irq_mask_ack(data); 68 69 mask = __raw_readw(KEYDETR); 70 for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS) 71 generic_handle_irq(irq_linear_revmap(x3proto_irq_domain, pin)); 72 73 chip->irq_unmask(data); 74 } 75 76 struct gpio_chip x3proto_gpio_chip = { 77 .label = "x3proto-gpio", 78 .direction_input = x3proto_gpio_direction_input, 79 .get = x3proto_gpio_get, 80 .to_irq = x3proto_gpio_to_irq, 81 .base = -1, 82 .ngpio = NR_BASEBOARD_GPIOS, 83 }; 84 85 static int x3proto_gpio_irq_map(struct irq_domain *domain, unsigned int virq, 86 irq_hw_number_t hwirq) 87 { 88 irq_set_chip_and_handler_name(virq, &dummy_irq_chip, handle_simple_irq, 89 "gpio"); 90 91 return 0; 92 } 93 94 static struct irq_domain_ops x3proto_gpio_irq_ops = { 95 .map = x3proto_gpio_irq_map, 96 .xlate = irq_domain_xlate_twocell, 97 }; 98 99 int __init x3proto_gpio_setup(void) 100 { 101 int ilsel, ret; 102 103 ilsel = ilsel_enable(ILSEL_KEY); 104 if (unlikely(ilsel < 0)) 105 return ilsel; 106 107 ret = gpiochip_add_data(&x3proto_gpio_chip, NULL); 108 if (unlikely(ret)) 109 goto err_gpio; 110 111 x3proto_irq_domain = irq_domain_add_linear(NULL, NR_BASEBOARD_GPIOS, 112 &x3proto_gpio_irq_ops, NULL); 113 if (unlikely(!x3proto_irq_domain)) 114 goto err_irq; 115 116 pr_info("registering '%s' support, handling GPIOs %u -> %u, " 117 "bound to IRQ %u\n", 118 x3proto_gpio_chip.label, x3proto_gpio_chip.base, 119 x3proto_gpio_chip.base + x3proto_gpio_chip.ngpio, 120 ilsel); 121 122 irq_set_chained_handler(ilsel, x3proto_gpio_irq_handler); 123 irq_set_irq_wake(ilsel, 1); 124 125 return 0; 126 127 err_irq: 128 gpiochip_remove(&x3proto_gpio_chip); 129 ret = 0; 130 err_gpio: 131 synchronize_irq(ilsel); 132 133 ilsel_disable(ILSEL_KEY); 134 135 return ret; 136 } 137