1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Coldfire generic GPIO support.
4 *
5 * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
6 */
7
8#include <linux/kernel.h>
9#include <linux/module.h>
10#include <linux/init.h>
11#include <linux/device.h>
12#include <linux/gpio/driver.h>
13
14#include <linux/io.h>
15#include <asm/coldfire.h>
16#include <asm/mcfsim.h>
17#include <asm/mcfgpio.h>
18
19int __mcfgpio_get_value(unsigned gpio)
20{
21	return mcfgpio_read(__mcfgpio_ppdr(gpio)) & mcfgpio_bit(gpio);
22}
23EXPORT_SYMBOL(__mcfgpio_get_value);
24
25void __mcfgpio_set_value(unsigned gpio, int value)
26{
27	if (gpio < MCFGPIO_SCR_START) {
28		unsigned long flags;
29		MCFGPIO_PORTTYPE data;
30
31		local_irq_save(flags);
32		data = mcfgpio_read(__mcfgpio_podr(gpio));
33		if (value)
34			data |= mcfgpio_bit(gpio);
35		else
36			data &= ~mcfgpio_bit(gpio);
37		mcfgpio_write(data, __mcfgpio_podr(gpio));
38		local_irq_restore(flags);
39	} else {
40		if (value)
41			mcfgpio_write(mcfgpio_bit(gpio),
42					MCFGPIO_SETR_PORT(gpio));
43		else
44			mcfgpio_write(~mcfgpio_bit(gpio),
45					MCFGPIO_CLRR_PORT(gpio));
46	}
47}
48EXPORT_SYMBOL(__mcfgpio_set_value);
49
50int __mcfgpio_direction_input(unsigned gpio)
51{
52	unsigned long flags;
53	MCFGPIO_PORTTYPE dir;
54
55	local_irq_save(flags);
56	dir = mcfgpio_read(__mcfgpio_pddr(gpio));
57	dir &= ~mcfgpio_bit(gpio);
58	mcfgpio_write(dir, __mcfgpio_pddr(gpio));
59	local_irq_restore(flags);
60
61	return 0;
62}
63EXPORT_SYMBOL(__mcfgpio_direction_input);
64
65int __mcfgpio_direction_output(unsigned gpio, int value)
66{
67	unsigned long flags;
68	MCFGPIO_PORTTYPE data;
69
70	local_irq_save(flags);
71	data = mcfgpio_read(__mcfgpio_pddr(gpio));
72	data |= mcfgpio_bit(gpio);
73	mcfgpio_write(data, __mcfgpio_pddr(gpio));
74
75	/* now set the data to output */
76	if (gpio < MCFGPIO_SCR_START) {
77		data = mcfgpio_read(__mcfgpio_podr(gpio));
78		if (value)
79			data |= mcfgpio_bit(gpio);
80		else
81			data &= ~mcfgpio_bit(gpio);
82		mcfgpio_write(data, __mcfgpio_podr(gpio));
83	} else {
84		 if (value)
85			mcfgpio_write(mcfgpio_bit(gpio),
86					MCFGPIO_SETR_PORT(gpio));
87		 else
88			 mcfgpio_write(~mcfgpio_bit(gpio),
89					 MCFGPIO_CLRR_PORT(gpio));
90	}
91	local_irq_restore(flags);
92	return 0;
93}
94EXPORT_SYMBOL(__mcfgpio_direction_output);
95
96int __mcfgpio_request(unsigned gpio)
97{
98	return 0;
99}
100EXPORT_SYMBOL(__mcfgpio_request);
101
102void __mcfgpio_free(unsigned gpio)
103{
104	__mcfgpio_direction_input(gpio);
105}
106EXPORT_SYMBOL(__mcfgpio_free);
107
108#ifdef CONFIG_GPIOLIB
109
110static int mcfgpio_direction_input(struct gpio_chip *chip, unsigned offset)
111{
112	return __mcfgpio_direction_input(offset);
113}
114
115static int mcfgpio_get_value(struct gpio_chip *chip, unsigned offset)
116{
117	return !!__mcfgpio_get_value(offset);
118}
119
120static int mcfgpio_direction_output(struct gpio_chip *chip, unsigned offset,
121				    int value)
122{
123	return __mcfgpio_direction_output(offset, value);
124}
125
126static void mcfgpio_set_value(struct gpio_chip *chip, unsigned offset,
127			      int value)
128{
129	__mcfgpio_set_value(offset, value);
130}
131
132static int mcfgpio_request(struct gpio_chip *chip, unsigned offset)
133{
134	return __mcfgpio_request(offset);
135}
136
137static void mcfgpio_free(struct gpio_chip *chip, unsigned offset)
138{
139	__mcfgpio_free(offset);
140}
141
142static int mcfgpio_to_irq(struct gpio_chip *chip, unsigned offset)
143{
144#if defined(MCFGPIO_IRQ_MIN)
145	if ((offset >= MCFGPIO_IRQ_MIN) && (offset < MCFGPIO_IRQ_MAX))
146#else
147	if (offset < MCFGPIO_IRQ_MAX)
148#endif
149		return MCFGPIO_IRQ_VECBASE + offset;
150	else
151		return -EINVAL;
152}
153
154static struct gpio_chip mcfgpio_chip = {
155	.label			= "mcfgpio",
156	.request		= mcfgpio_request,
157	.free			= mcfgpio_free,
158	.direction_input	= mcfgpio_direction_input,
159	.direction_output	= mcfgpio_direction_output,
160	.get			= mcfgpio_get_value,
161	.set			= mcfgpio_set_value,
162	.to_irq			= mcfgpio_to_irq,
163	.base			= 0,
164	.ngpio			= MCFGPIO_PIN_MAX,
165};
166
167static int __init mcfgpio_sysinit(void)
168{
169	return gpiochip_add_data(&mcfgpio_chip, NULL);
170}
171
172core_initcall(mcfgpio_sysinit);
173#endif
174