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

sh: mach-x3proto: Support for baseboard GPIOs.

This adds trivial support for the GPIOs implemented through the baseboard
CPLD, used for driving the button matrix.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>

+149
+2
arch/sh/boards/mach-x3proto/Makefile
··· 1 1 obj-y += setup.o ilsel.o 2 + 3 + obj-$(CONFIG_GENERIC_GPIO) += gpio.o
+135
arch/sh/boards/mach-x3proto/gpio.c
··· 1 + /* 2 + * arch/sh/boards/mach-x3proto/gpio.c 3 + * 4 + * Renesas SH-X3 Prototype Baseboard GPIO Support. 5 + * 6 + * Copyright (C) 2010 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/io.h> 21 + #include <mach/ilsel.h> 22 + #include <mach/hardware.h> 23 + 24 + #define KEYCTLR 0xb81c0000 25 + #define KEYOUTR 0xb81c0002 26 + #define KEYDETR 0xb81c0004 27 + 28 + static DEFINE_SPINLOCK(x3proto_gpio_lock); 29 + static unsigned int x3proto_gpio_irq_map[NR_BASEBOARD_GPIOS] = { 0, }; 30 + 31 + static int x3proto_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) 32 + { 33 + unsigned long flags; 34 + unsigned int data; 35 + 36 + spin_lock_irqsave(&x3proto_gpio_lock, flags); 37 + data = __raw_readw(KEYCTLR); 38 + data |= (1 << gpio); 39 + __raw_writew(data, KEYCTLR); 40 + spin_unlock_irqrestore(&x3proto_gpio_lock, flags); 41 + 42 + return 0; 43 + } 44 + 45 + static int x3proto_gpio_get(struct gpio_chip *chip, unsigned gpio) 46 + { 47 + return !!(__raw_readw(KEYDETR) & (1 << gpio)); 48 + } 49 + 50 + static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) 51 + { 52 + return x3proto_gpio_irq_map[gpio]; 53 + } 54 + 55 + static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) 56 + { 57 + struct irq_chip *chip = get_irq_desc_chip(desc); 58 + unsigned long mask; 59 + int pin; 60 + 61 + chip->mask_ack(irq); 62 + 63 + mask = __raw_readw(KEYDETR); 64 + 65 + for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS) 66 + generic_handle_irq(x3proto_gpio_to_irq(NULL, pin)); 67 + 68 + chip->unmask(irq); 69 + } 70 + 71 + struct gpio_chip x3proto_gpio_chip = { 72 + .label = "x3proto-gpio", 73 + .direction_input = x3proto_gpio_direction_input, 74 + .get = x3proto_gpio_get, 75 + .to_irq = x3proto_gpio_to_irq, 76 + .base = -1, 77 + .ngpio = NR_BASEBOARD_GPIOS, 78 + }; 79 + 80 + int __init x3proto_gpio_setup(void) 81 + { 82 + unsigned int ilsel; 83 + int ret, i; 84 + 85 + ilsel = ilsel_enable(ILSEL_KEY); 86 + if (unlikely(ilsel < 0)) 87 + return ilsel; 88 + 89 + ret = gpiochip_add(&x3proto_gpio_chip); 90 + if (unlikely(ret)) 91 + goto err_gpio; 92 + 93 + for (i = 0; i < NR_BASEBOARD_GPIOS; i++) { 94 + unsigned long flags; 95 + unsigned int irq = create_irq(); 96 + 97 + if (unlikely(irq < 0)) { 98 + ret = -EINVAL; 99 + goto err_irq; 100 + } 101 + 102 + spin_lock_irqsave(&x3proto_gpio_lock, flags); 103 + x3proto_gpio_irq_map[i] = irq; 104 + set_irq_chip_and_handler_name(irq, &dummy_irq_chip, 105 + handle_simple_irq, "gpio"); 106 + spin_unlock_irqrestore(&x3proto_gpio_lock, flags); 107 + } 108 + 109 + pr_info("registering '%s' support, handling GPIOs %u -> %u, " 110 + "bound to IRQ %u\n", 111 + x3proto_gpio_chip.label, x3proto_gpio_chip.base, 112 + x3proto_gpio_chip.base + x3proto_gpio_chip.ngpio, 113 + ilsel); 114 + 115 + set_irq_chained_handler(ilsel, x3proto_gpio_irq_handler); 116 + set_irq_wake(ilsel, 1); 117 + 118 + return 0; 119 + 120 + err_irq: 121 + for (; i >= 0; --i) 122 + if (x3proto_gpio_irq_map[i]) 123 + destroy_irq(x3proto_gpio_irq_map[i]); 124 + 125 + ret = gpiochip_remove(&x3proto_gpio_chip); 126 + if (unlikely(ret)) 127 + pr_err("Failed deregistering GPIO\n"); 128 + 129 + err_gpio: 130 + synchronize_irq(ilsel); 131 + 132 + ilsel_disable(ILSEL_KEY); 133 + 134 + return ret; 135 + }
+12
arch/sh/include/mach-x3proto/mach/hardware.h
··· 1 + #ifndef __MACH_X3PROTO_HARDWARE_H 2 + #define __MACH_X3PROTO_HARDWARE_H 3 + 4 + struct gpio_chip; 5 + 6 + /* arch/sh/boards/mach-x3proto/gpio.c */ 7 + int x3proto_gpio_setup(void); 8 + extern struct gpio_chip x3proto_gpio_chip; 9 + 10 + #define NR_BASEBOARD_GPIOS 16 11 + 12 + #endif /* __MACH_X3PROTO_HARDWARE_H */