162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Coldfire generic GPIO support. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (C) Copyright 2009, Steven King <sfking@fdwdc.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/device.h> 1262306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/io.h> 1562306a36Sopenharmony_ci#include <asm/coldfire.h> 1662306a36Sopenharmony_ci#include <asm/mcfsim.h> 1762306a36Sopenharmony_ci#include <asm/mcfgpio.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciint __mcfgpio_get_value(unsigned gpio) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci return mcfgpio_read(__mcfgpio_ppdr(gpio)) & mcfgpio_bit(gpio); 2262306a36Sopenharmony_ci} 2362306a36Sopenharmony_ciEXPORT_SYMBOL(__mcfgpio_get_value); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_civoid __mcfgpio_set_value(unsigned gpio, int value) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci if (gpio < MCFGPIO_SCR_START) { 2862306a36Sopenharmony_ci unsigned long flags; 2962306a36Sopenharmony_ci MCFGPIO_PORTTYPE data; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci local_irq_save(flags); 3262306a36Sopenharmony_ci data = mcfgpio_read(__mcfgpio_podr(gpio)); 3362306a36Sopenharmony_ci if (value) 3462306a36Sopenharmony_ci data |= mcfgpio_bit(gpio); 3562306a36Sopenharmony_ci else 3662306a36Sopenharmony_ci data &= ~mcfgpio_bit(gpio); 3762306a36Sopenharmony_ci mcfgpio_write(data, __mcfgpio_podr(gpio)); 3862306a36Sopenharmony_ci local_irq_restore(flags); 3962306a36Sopenharmony_ci } else { 4062306a36Sopenharmony_ci if (value) 4162306a36Sopenharmony_ci mcfgpio_write(mcfgpio_bit(gpio), 4262306a36Sopenharmony_ci MCFGPIO_SETR_PORT(gpio)); 4362306a36Sopenharmony_ci else 4462306a36Sopenharmony_ci mcfgpio_write(~mcfgpio_bit(gpio), 4562306a36Sopenharmony_ci MCFGPIO_CLRR_PORT(gpio)); 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ciEXPORT_SYMBOL(__mcfgpio_set_value); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ciint __mcfgpio_direction_input(unsigned gpio) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci unsigned long flags; 5362306a36Sopenharmony_ci MCFGPIO_PORTTYPE dir; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci local_irq_save(flags); 5662306a36Sopenharmony_ci dir = mcfgpio_read(__mcfgpio_pddr(gpio)); 5762306a36Sopenharmony_ci dir &= ~mcfgpio_bit(gpio); 5862306a36Sopenharmony_ci mcfgpio_write(dir, __mcfgpio_pddr(gpio)); 5962306a36Sopenharmony_ci local_irq_restore(flags); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return 0; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ciEXPORT_SYMBOL(__mcfgpio_direction_input); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciint __mcfgpio_direction_output(unsigned gpio, int value) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci unsigned long flags; 6862306a36Sopenharmony_ci MCFGPIO_PORTTYPE data; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci local_irq_save(flags); 7162306a36Sopenharmony_ci data = mcfgpio_read(__mcfgpio_pddr(gpio)); 7262306a36Sopenharmony_ci data |= mcfgpio_bit(gpio); 7362306a36Sopenharmony_ci mcfgpio_write(data, __mcfgpio_pddr(gpio)); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* now set the data to output */ 7662306a36Sopenharmony_ci if (gpio < MCFGPIO_SCR_START) { 7762306a36Sopenharmony_ci data = mcfgpio_read(__mcfgpio_podr(gpio)); 7862306a36Sopenharmony_ci if (value) 7962306a36Sopenharmony_ci data |= mcfgpio_bit(gpio); 8062306a36Sopenharmony_ci else 8162306a36Sopenharmony_ci data &= ~mcfgpio_bit(gpio); 8262306a36Sopenharmony_ci mcfgpio_write(data, __mcfgpio_podr(gpio)); 8362306a36Sopenharmony_ci } else { 8462306a36Sopenharmony_ci if (value) 8562306a36Sopenharmony_ci mcfgpio_write(mcfgpio_bit(gpio), 8662306a36Sopenharmony_ci MCFGPIO_SETR_PORT(gpio)); 8762306a36Sopenharmony_ci else 8862306a36Sopenharmony_ci mcfgpio_write(~mcfgpio_bit(gpio), 8962306a36Sopenharmony_ci MCFGPIO_CLRR_PORT(gpio)); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci local_irq_restore(flags); 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ciEXPORT_SYMBOL(__mcfgpio_direction_output); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ciint __mcfgpio_request(unsigned gpio) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ciEXPORT_SYMBOL(__mcfgpio_request); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_civoid __mcfgpio_free(unsigned gpio) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci __mcfgpio_direction_input(gpio); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ciEXPORT_SYMBOL(__mcfgpio_free); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci#ifdef CONFIG_GPIOLIB 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic int mcfgpio_direction_input(struct gpio_chip *chip, unsigned offset) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci return __mcfgpio_direction_input(offset); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic int mcfgpio_get_value(struct gpio_chip *chip, unsigned offset) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci return !!__mcfgpio_get_value(offset); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic int mcfgpio_direction_output(struct gpio_chip *chip, unsigned offset, 12162306a36Sopenharmony_ci int value) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci return __mcfgpio_direction_output(offset, value); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void mcfgpio_set_value(struct gpio_chip *chip, unsigned offset, 12762306a36Sopenharmony_ci int value) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci __mcfgpio_set_value(offset, value); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic int mcfgpio_request(struct gpio_chip *chip, unsigned offset) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci return __mcfgpio_request(offset); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic void mcfgpio_free(struct gpio_chip *chip, unsigned offset) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci __mcfgpio_free(offset); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int mcfgpio_to_irq(struct gpio_chip *chip, unsigned offset) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci#if defined(MCFGPIO_IRQ_MIN) 14562306a36Sopenharmony_ci if ((offset >= MCFGPIO_IRQ_MIN) && (offset < MCFGPIO_IRQ_MAX)) 14662306a36Sopenharmony_ci#else 14762306a36Sopenharmony_ci if (offset < MCFGPIO_IRQ_MAX) 14862306a36Sopenharmony_ci#endif 14962306a36Sopenharmony_ci return MCFGPIO_IRQ_VECBASE + offset; 15062306a36Sopenharmony_ci else 15162306a36Sopenharmony_ci return -EINVAL; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic struct gpio_chip mcfgpio_chip = { 15562306a36Sopenharmony_ci .label = "mcfgpio", 15662306a36Sopenharmony_ci .request = mcfgpio_request, 15762306a36Sopenharmony_ci .free = mcfgpio_free, 15862306a36Sopenharmony_ci .direction_input = mcfgpio_direction_input, 15962306a36Sopenharmony_ci .direction_output = mcfgpio_direction_output, 16062306a36Sopenharmony_ci .get = mcfgpio_get_value, 16162306a36Sopenharmony_ci .set = mcfgpio_set_value, 16262306a36Sopenharmony_ci .to_irq = mcfgpio_to_irq, 16362306a36Sopenharmony_ci .base = 0, 16462306a36Sopenharmony_ci .ngpio = MCFGPIO_PIN_MAX, 16562306a36Sopenharmony_ci}; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic int __init mcfgpio_sysinit(void) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci return gpiochip_add_data(&mcfgpio_chip, NULL); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cicore_initcall(mcfgpio_sysinit); 17362306a36Sopenharmony_ci#endif 174