/* * Coldfire generic GPIO support. * * (C) Copyright 2009, Steven King <sfking@fdwdc.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/device.h> #include <linux/io.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfgpio.h> int __mcfgpio_get_value(unsigned gpio) { return mcfgpio_read(__mcfgpio_ppdr(gpio)) & mcfgpio_bit(gpio); } EXPORT_SYMBOL(__mcfgpio_get_value); void __mcfgpio_set_value(unsigned gpio, int value) { if (gpio < MCFGPIO_SCR_START) { unsigned long flags; MCFGPIO_PORTTYPE data; local_irq_save(flags); data = mcfgpio_read(__mcfgpio_podr(gpio)); if (value) data |= mcfgpio_bit(gpio); else data &= ~mcfgpio_bit(gpio); mcfgpio_write(data, __mcfgpio_podr(gpio)); local_irq_restore(flags); } else { if (value) mcfgpio_write(mcfgpio_bit(gpio), MCFGPIO_SETR_PORT(gpio)); else mcfgpio_write(~mcfgpio_bit(gpio), MCFGPIO_CLRR_PORT(gpio)); } } EXPORT_SYMBOL(__mcfgpio_set_value); int __mcfgpio_direction_input(unsigned gpio) { unsigned long flags; MCFGPIO_PORTTYPE dir; local_irq_save(flags); dir = mcfgpio_read(__mcfgpio_pddr(gpio)); dir &= ~mcfgpio_bit(gpio); mcfgpio_write(dir, __mcfgpio_pddr(gpio)); local_irq_restore(flags); return 0; } EXPORT_SYMBOL(__mcfgpio_direction_input); int __mcfgpio_direction_output(unsigned gpio, int value) { unsigned long flags; MCFGPIO_PORTTYPE data; local_irq_save(flags); data = mcfgpio_read(__mcfgpio_pddr(gpio)); data |= mcfgpio_bit(gpio); mcfgpio_write(data, __mcfgpio_pddr(gpio)); /* now set the data to output */ if (gpio < MCFGPIO_SCR_START) { data = mcfgpio_read(__mcfgpio_podr(gpio)); if (value) data |= mcfgpio_bit(gpio); else data &= ~mcfgpio_bit(gpio); mcfgpio_write(data, __mcfgpio_podr(gpio)); } else { if (value) mcfgpio_write(mcfgpio_bit(gpio), MCFGPIO_SETR_PORT(gpio)); else mcfgpio_write(~mcfgpio_bit(gpio), MCFGPIO_CLRR_PORT(gpio)); } local_irq_restore(flags); return 0; } EXPORT_SYMBOL(__mcfgpio_direction_output); int __mcfgpio_request(unsigned gpio) { return 0; } EXPORT_SYMBOL(__mcfgpio_request); void __mcfgpio_free(unsigned gpio) { __mcfgpio_direction_input(gpio); } EXPORT_SYMBOL(__mcfgpio_free); #ifdef CONFIG_GPIOLIB static int mcfgpio_direction_input(struct gpio_chip *chip, unsigned offset) { return __mcfgpio_direction_input(offset); } static int mcfgpio_get_value(struct gpio_chip *chip, unsigned offset) { return __mcfgpio_get_value(offset); } static int mcfgpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) { return __mcfgpio_direction_output(offset, value); } static void mcfgpio_set_value(struct gpio_chip *chip, unsigned offset, int value) { __mcfgpio_set_value(offset, value); } static int mcfgpio_request(struct gpio_chip *chip, unsigned offset) { return __mcfgpio_request(offset); } static void mcfgpio_free(struct gpio_chip *chip, unsigned offset) { __mcfgpio_free(offset); } static int mcfgpio_to_irq(struct gpio_chip *chip, unsigned offset) { #if defined(MCFGPIO_IRQ_MIN) if ((offset >= MCFGPIO_IRQ_MIN) && (offset < MCFGPIO_IRQ_MAX)) #else if (offset < MCFGPIO_IRQ_MAX) #endif return MCFGPIO_IRQ_VECBASE + offset; else return -EINVAL; } static struct bus_type mcfgpio_subsys = { .name = "gpio", .dev_name = "gpio", }; static struct gpio_chip mcfgpio_chip = { .label = "mcfgpio", .request = mcfgpio_request, .free = mcfgpio_free, .direction_input = mcfgpio_direction_input, .direction_output = mcfgpio_direction_output, .get = mcfgpio_get_value, .set = mcfgpio_set_value, .to_irq = mcfgpio_to_irq, .base = 0, .ngpio = MCFGPIO_PIN_MAX, }; static int __init mcfgpio_sysinit(void) { gpiochip_add(&mcfgpio_chip); return subsys_system_register(&mcfgpio_subsys, NULL); } core_initcall(mcfgpio_sysinit); #endif