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