Path: blob/master/arch/sh/boards/mach-x3proto/gpio.c
15126 views
/*1* arch/sh/boards/mach-x3proto/gpio.c2*3* Renesas SH-X3 Prototype Baseboard GPIO Support.4*5* Copyright (C) 2010 Paul Mundt6*7* This file is subject to the terms and conditions of the GNU General Public8* License. See the file "COPYING" in the main directory of this archive9* for more details.10*/11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt1213#include <linux/init.h>14#include <linux/interrupt.h>15#include <linux/gpio.h>16#include <linux/irq.h>17#include <linux/kernel.h>18#include <linux/spinlock.h>19#include <linux/io.h>20#include <mach/ilsel.h>21#include <mach/hardware.h>2223#define KEYCTLR 0xb81c000024#define KEYOUTR 0xb81c000225#define KEYDETR 0xb81c00042627static DEFINE_SPINLOCK(x3proto_gpio_lock);28static unsigned int x3proto_gpio_irq_map[NR_BASEBOARD_GPIOS] = { 0, };2930static int x3proto_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)31{32unsigned long flags;33unsigned int data;3435spin_lock_irqsave(&x3proto_gpio_lock, flags);36data = __raw_readw(KEYCTLR);37data |= (1 << gpio);38__raw_writew(data, KEYCTLR);39spin_unlock_irqrestore(&x3proto_gpio_lock, flags);4041return 0;42}4344static int x3proto_gpio_get(struct gpio_chip *chip, unsigned gpio)45{46return !!(__raw_readw(KEYDETR) & (1 << gpio));47}4849static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)50{51return x3proto_gpio_irq_map[gpio];52}5354static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)55{56struct irq_data *data = irq_get_irq_data(irq);57struct irq_chip *chip = irq_data_get_irq_chip(data);58unsigned long mask;59int pin;6061chip->irq_mask_ack(data);6263mask = __raw_readw(KEYDETR);6465for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS)66generic_handle_irq(x3proto_gpio_to_irq(NULL, pin));6768chip->irq_unmask(data);69}7071struct 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};7980int __init x3proto_gpio_setup(void)81{82int ilsel;83int ret, i;8485ilsel = ilsel_enable(ILSEL_KEY);86if (unlikely(ilsel < 0))87return ilsel;8889ret = gpiochip_add(&x3proto_gpio_chip);90if (unlikely(ret))91goto err_gpio;9293for (i = 0; i < NR_BASEBOARD_GPIOS; i++) {94unsigned long flags;95int irq = create_irq();9697if (unlikely(irq < 0)) {98ret = -EINVAL;99goto err_irq;100}101102spin_lock_irqsave(&x3proto_gpio_lock, flags);103x3proto_gpio_irq_map[i] = irq;104irq_set_chip_and_handler_name(irq, &dummy_irq_chip,105handle_simple_irq, "gpio");106spin_unlock_irqrestore(&x3proto_gpio_lock, flags);107}108109pr_info("registering '%s' support, handling GPIOs %u -> %u, "110"bound to IRQ %u\n",111x3proto_gpio_chip.label, x3proto_gpio_chip.base,112x3proto_gpio_chip.base + x3proto_gpio_chip.ngpio,113ilsel);114115irq_set_chained_handler(ilsel, x3proto_gpio_irq_handler);116irq_set_irq_wake(ilsel, 1);117118return 0;119120err_irq:121for (; i >= 0; --i)122if (x3proto_gpio_irq_map[i])123destroy_irq(x3proto_gpio_irq_map[i]);124125ret = gpiochip_remove(&x3proto_gpio_chip);126if (unlikely(ret))127pr_err("Failed deregistering GPIO\n");128129err_gpio:130synchronize_irq(ilsel);131132ilsel_disable(ILSEL_KEY);133134return ret;135}136137138