|  | /* | 
|  | * 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 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) | 
|  | { | 
|  | return gpiochip_add_data(&mcfgpio_chip, NULL); | 
|  | } | 
|  |  | 
|  | core_initcall(mcfgpio_sysinit); | 
|  | #endif |