18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Coldfire generic GPIO support. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (C) Copyright 2009, Steven King <sfking@fdwdc.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/device.h> 128c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <asm/coldfire.h> 168c2ecf20Sopenharmony_ci#include <asm/mcfsim.h> 178c2ecf20Sopenharmony_ci#include <asm/mcfgpio.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ciint __mcfgpio_get_value(unsigned gpio) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci return mcfgpio_read(__mcfgpio_ppdr(gpio)) & mcfgpio_bit(gpio); 228c2ecf20Sopenharmony_ci} 238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__mcfgpio_get_value); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_civoid __mcfgpio_set_value(unsigned gpio, int value) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci if (gpio < MCFGPIO_SCR_START) { 288c2ecf20Sopenharmony_ci unsigned long flags; 298c2ecf20Sopenharmony_ci MCFGPIO_PORTTYPE data; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci local_irq_save(flags); 328c2ecf20Sopenharmony_ci data = mcfgpio_read(__mcfgpio_podr(gpio)); 338c2ecf20Sopenharmony_ci if (value) 348c2ecf20Sopenharmony_ci data |= mcfgpio_bit(gpio); 358c2ecf20Sopenharmony_ci else 368c2ecf20Sopenharmony_ci data &= ~mcfgpio_bit(gpio); 378c2ecf20Sopenharmony_ci mcfgpio_write(data, __mcfgpio_podr(gpio)); 388c2ecf20Sopenharmony_ci local_irq_restore(flags); 398c2ecf20Sopenharmony_ci } else { 408c2ecf20Sopenharmony_ci if (value) 418c2ecf20Sopenharmony_ci mcfgpio_write(mcfgpio_bit(gpio), 428c2ecf20Sopenharmony_ci MCFGPIO_SETR_PORT(gpio)); 438c2ecf20Sopenharmony_ci else 448c2ecf20Sopenharmony_ci mcfgpio_write(~mcfgpio_bit(gpio), 458c2ecf20Sopenharmony_ci MCFGPIO_CLRR_PORT(gpio)); 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__mcfgpio_set_value); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciint __mcfgpio_direction_input(unsigned gpio) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci unsigned long flags; 538c2ecf20Sopenharmony_ci MCFGPIO_PORTTYPE dir; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci local_irq_save(flags); 568c2ecf20Sopenharmony_ci dir = mcfgpio_read(__mcfgpio_pddr(gpio)); 578c2ecf20Sopenharmony_ci dir &= ~mcfgpio_bit(gpio); 588c2ecf20Sopenharmony_ci mcfgpio_write(dir, __mcfgpio_pddr(gpio)); 598c2ecf20Sopenharmony_ci local_irq_restore(flags); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return 0; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__mcfgpio_direction_input); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ciint __mcfgpio_direction_output(unsigned gpio, int value) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci unsigned long flags; 688c2ecf20Sopenharmony_ci MCFGPIO_PORTTYPE data; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci local_irq_save(flags); 718c2ecf20Sopenharmony_ci data = mcfgpio_read(__mcfgpio_pddr(gpio)); 728c2ecf20Sopenharmony_ci data |= mcfgpio_bit(gpio); 738c2ecf20Sopenharmony_ci mcfgpio_write(data, __mcfgpio_pddr(gpio)); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* now set the data to output */ 768c2ecf20Sopenharmony_ci if (gpio < MCFGPIO_SCR_START) { 778c2ecf20Sopenharmony_ci data = mcfgpio_read(__mcfgpio_podr(gpio)); 788c2ecf20Sopenharmony_ci if (value) 798c2ecf20Sopenharmony_ci data |= mcfgpio_bit(gpio); 808c2ecf20Sopenharmony_ci else 818c2ecf20Sopenharmony_ci data &= ~mcfgpio_bit(gpio); 828c2ecf20Sopenharmony_ci mcfgpio_write(data, __mcfgpio_podr(gpio)); 838c2ecf20Sopenharmony_ci } else { 848c2ecf20Sopenharmony_ci if (value) 858c2ecf20Sopenharmony_ci mcfgpio_write(mcfgpio_bit(gpio), 868c2ecf20Sopenharmony_ci MCFGPIO_SETR_PORT(gpio)); 878c2ecf20Sopenharmony_ci else 888c2ecf20Sopenharmony_ci mcfgpio_write(~mcfgpio_bit(gpio), 898c2ecf20Sopenharmony_ci MCFGPIO_CLRR_PORT(gpio)); 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci local_irq_restore(flags); 928c2ecf20Sopenharmony_ci return 0; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__mcfgpio_direction_output); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciint __mcfgpio_request(unsigned gpio) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci return 0; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__mcfgpio_request); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_civoid __mcfgpio_free(unsigned gpio) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci __mcfgpio_direction_input(gpio); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__mcfgpio_free); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#ifdef CONFIG_GPIOLIB 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int mcfgpio_direction_input(struct gpio_chip *chip, unsigned offset) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci return __mcfgpio_direction_input(offset); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int mcfgpio_get_value(struct gpio_chip *chip, unsigned offset) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci return !!__mcfgpio_get_value(offset); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic int mcfgpio_direction_output(struct gpio_chip *chip, unsigned offset, 1218c2ecf20Sopenharmony_ci int value) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci return __mcfgpio_direction_output(offset, value); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic void mcfgpio_set_value(struct gpio_chip *chip, unsigned offset, 1278c2ecf20Sopenharmony_ci int value) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci __mcfgpio_set_value(offset, value); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int mcfgpio_request(struct gpio_chip *chip, unsigned offset) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci return __mcfgpio_request(offset); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void mcfgpio_free(struct gpio_chip *chip, unsigned offset) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci __mcfgpio_free(offset); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int mcfgpio_to_irq(struct gpio_chip *chip, unsigned offset) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci#if defined(MCFGPIO_IRQ_MIN) 1458c2ecf20Sopenharmony_ci if ((offset >= MCFGPIO_IRQ_MIN) && (offset < MCFGPIO_IRQ_MAX)) 1468c2ecf20Sopenharmony_ci#else 1478c2ecf20Sopenharmony_ci if (offset < MCFGPIO_IRQ_MAX) 1488c2ecf20Sopenharmony_ci#endif 1498c2ecf20Sopenharmony_ci return MCFGPIO_IRQ_VECBASE + offset; 1508c2ecf20Sopenharmony_ci else 1518c2ecf20Sopenharmony_ci return -EINVAL; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic struct gpio_chip mcfgpio_chip = { 1558c2ecf20Sopenharmony_ci .label = "mcfgpio", 1568c2ecf20Sopenharmony_ci .request = mcfgpio_request, 1578c2ecf20Sopenharmony_ci .free = mcfgpio_free, 1588c2ecf20Sopenharmony_ci .direction_input = mcfgpio_direction_input, 1598c2ecf20Sopenharmony_ci .direction_output = mcfgpio_direction_output, 1608c2ecf20Sopenharmony_ci .get = mcfgpio_get_value, 1618c2ecf20Sopenharmony_ci .set = mcfgpio_set_value, 1628c2ecf20Sopenharmony_ci .to_irq = mcfgpio_to_irq, 1638c2ecf20Sopenharmony_ci .base = 0, 1648c2ecf20Sopenharmony_ci .ngpio = MCFGPIO_PIN_MAX, 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic int __init mcfgpio_sysinit(void) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci return gpiochip_add_data(&mcfgpio_chip, NULL); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cicore_initcall(mcfgpio_sysinit); 1738c2ecf20Sopenharmony_ci#endif 174