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