xref: /openbmc/linux/drivers/gpio/gpio-vx855.c (revision 872982ce)
1c872a20fSLinus Walleij // SPDX-License-Identifier: GPL-2.0+
2c103de24SGrant Likely /*
3c103de24SGrant Likely  * Linux GPIOlib driver for the VIA VX855 integrated southbridge GPIO
4c103de24SGrant Likely  *
5c103de24SGrant Likely  * Copyright (C) 2009 VIA Technologies, Inc.
6c103de24SGrant Likely  * Copyright (C) 2010 One Laptop per Child
7c103de24SGrant Likely  * Author: Harald Welte <HaraldWelte@viatech.com>
8c103de24SGrant Likely  * All rights reserved.
9c103de24SGrant Likely  */
10c103de24SGrant Likely #include <linux/kernel.h>
11c103de24SGrant Likely #include <linux/module.h>
123bca2d4eSLinus Walleij #include <linux/gpio/driver.h>
13c103de24SGrant Likely #include <linux/slab.h>
14c103de24SGrant Likely #include <linux/device.h>
15c103de24SGrant Likely #include <linux/platform_device.h>
16c103de24SGrant Likely #include <linux/pci.h>
17c103de24SGrant Likely #include <linux/io.h>
18c103de24SGrant Likely 
19c103de24SGrant Likely #define MODULE_NAME "vx855_gpio"
20c103de24SGrant Likely 
21c103de24SGrant Likely /* The VX855 south bridge has the following GPIO pins:
22c103de24SGrant Likely  *	GPI 0...13	General Purpose Input
23c103de24SGrant Likely  *	GPO 0...12	General Purpose Output
24c103de24SGrant Likely  *	GPIO 0...14	General Purpose I/O (Open-Drain)
25c103de24SGrant Likely  */
26c103de24SGrant Likely 
27c103de24SGrant Likely #define NR_VX855_GPI	14
28c103de24SGrant Likely #define NR_VX855_GPO	13
29c103de24SGrant Likely #define NR_VX855_GPIO	15
30c103de24SGrant Likely 
31c103de24SGrant Likely #define NR_VX855_GPInO	(NR_VX855_GPI + NR_VX855_GPO)
32c103de24SGrant Likely #define NR_VX855_GP	(NR_VX855_GPI + NR_VX855_GPO + NR_VX855_GPIO)
33c103de24SGrant Likely 
34c103de24SGrant Likely struct vx855_gpio {
35c103de24SGrant Likely 	struct gpio_chip gpio;
36c103de24SGrant Likely 	spinlock_t lock;
37c103de24SGrant Likely 	u32 io_gpi;
38c103de24SGrant Likely 	u32 io_gpo;
39c103de24SGrant Likely };
40c103de24SGrant Likely 
41c103de24SGrant Likely /* resolve a GPIx into the corresponding bit position */
gpi_i_bit(int i)42c103de24SGrant Likely static inline u_int32_t gpi_i_bit(int i)
43c103de24SGrant Likely {
44c103de24SGrant Likely 	if (i < 10)
45c103de24SGrant Likely 		return 1 << i;
46c103de24SGrant Likely 	else
47c103de24SGrant Likely 		return 1 << (i + 14);
48c103de24SGrant Likely }
49c103de24SGrant Likely 
gpo_o_bit(int i)50c103de24SGrant Likely static inline u_int32_t gpo_o_bit(int i)
51c103de24SGrant Likely {
52c103de24SGrant Likely 	if (i < 11)
53c103de24SGrant Likely 		return 1 << i;
54c103de24SGrant Likely 	else
55c103de24SGrant Likely 		return 1 << (i + 14);
56c103de24SGrant Likely }
57c103de24SGrant Likely 
gpio_i_bit(int i)58c103de24SGrant Likely static inline u_int32_t gpio_i_bit(int i)
59c103de24SGrant Likely {
60c103de24SGrant Likely 	if (i < 14)
61c103de24SGrant Likely 		return 1 << (i + 10);
62c103de24SGrant Likely 	else
63c103de24SGrant Likely 		return 1 << (i + 14);
64c103de24SGrant Likely }
65c103de24SGrant Likely 
gpio_o_bit(int i)66c103de24SGrant Likely static inline u_int32_t gpio_o_bit(int i)
67c103de24SGrant Likely {
68c103de24SGrant Likely 	if (i < 14)
69c103de24SGrant Likely 		return 1 << (i + 11);
70c103de24SGrant Likely 	else
71c103de24SGrant Likely 		return 1 << (i + 13);
72c103de24SGrant Likely }
73c103de24SGrant Likely 
74e81ccba6SSachin agarwal /* Mapping between numeric GPIO ID and the actual GPIO hardware numbering:
75c103de24SGrant Likely  * 0..13	GPI 0..13
76c103de24SGrant Likely  * 14..26	GPO 0..12
77c103de24SGrant Likely  * 27..41	GPIO 0..14
78c103de24SGrant Likely  */
79c103de24SGrant Likely 
vx855gpio_direction_input(struct gpio_chip * gpio,unsigned int nr)80c103de24SGrant Likely static int vx855gpio_direction_input(struct gpio_chip *gpio,
81c103de24SGrant Likely 				     unsigned int nr)
82c103de24SGrant Likely {
839355879eSLinus Walleij 	struct vx855_gpio *vg = gpiochip_get_data(gpio);
84c103de24SGrant Likely 	unsigned long flags;
85c103de24SGrant Likely 	u_int32_t reg_out;
86c103de24SGrant Likely 
87c103de24SGrant Likely 	/* Real GPI bits are always in input direction */
88c103de24SGrant Likely 	if (nr < NR_VX855_GPI)
89c103de24SGrant Likely 		return 0;
90c103de24SGrant Likely 
91c103de24SGrant Likely 	/* Real GPO bits cannot be put in output direction */
92c103de24SGrant Likely 	if (nr < NR_VX855_GPInO)
93c103de24SGrant Likely 		return -EINVAL;
94c103de24SGrant Likely 
95c103de24SGrant Likely 	/* Open Drain GPIO have to be set to one */
96c103de24SGrant Likely 	spin_lock_irqsave(&vg->lock, flags);
97c103de24SGrant Likely 	reg_out = inl(vg->io_gpo);
98c103de24SGrant Likely 	reg_out |= gpio_o_bit(nr - NR_VX855_GPInO);
99c103de24SGrant Likely 	outl(reg_out, vg->io_gpo);
100c103de24SGrant Likely 	spin_unlock_irqrestore(&vg->lock, flags);
101c103de24SGrant Likely 
102c103de24SGrant Likely 	return 0;
103c103de24SGrant Likely }
104c103de24SGrant Likely 
vx855gpio_get(struct gpio_chip * gpio,unsigned int nr)105c103de24SGrant Likely static int vx855gpio_get(struct gpio_chip *gpio, unsigned int nr)
106c103de24SGrant Likely {
1079355879eSLinus Walleij 	struct vx855_gpio *vg = gpiochip_get_data(gpio);
108c103de24SGrant Likely 	u_int32_t reg_in;
109c103de24SGrant Likely 	int ret = 0;
110c103de24SGrant Likely 
111c103de24SGrant Likely 	if (nr < NR_VX855_GPI) {
112c103de24SGrant Likely 		reg_in = inl(vg->io_gpi);
113c103de24SGrant Likely 		if (reg_in & gpi_i_bit(nr))
114c103de24SGrant Likely 			ret = 1;
115c103de24SGrant Likely 	} else if (nr < NR_VX855_GPInO) {
116c103de24SGrant Likely 		/* GPO don't have an input bit, we need to read it
117c103de24SGrant Likely 		 * back from the output register */
118c103de24SGrant Likely 		reg_in = inl(vg->io_gpo);
119c103de24SGrant Likely 		if (reg_in & gpo_o_bit(nr - NR_VX855_GPI))
120c103de24SGrant Likely 			ret = 1;
121c103de24SGrant Likely 	} else {
122c103de24SGrant Likely 		reg_in = inl(vg->io_gpi);
123c103de24SGrant Likely 		if (reg_in & gpio_i_bit(nr - NR_VX855_GPInO))
124c103de24SGrant Likely 			ret = 1;
125c103de24SGrant Likely 	}
126c103de24SGrant Likely 
127c103de24SGrant Likely 	return ret;
128c103de24SGrant Likely }
129c103de24SGrant Likely 
vx855gpio_set(struct gpio_chip * gpio,unsigned int nr,int val)130c103de24SGrant Likely static void vx855gpio_set(struct gpio_chip *gpio, unsigned int nr,
131c103de24SGrant Likely 			  int val)
132c103de24SGrant Likely {
1339355879eSLinus Walleij 	struct vx855_gpio *vg = gpiochip_get_data(gpio);
134c103de24SGrant Likely 	unsigned long flags;
135c103de24SGrant Likely 	u_int32_t reg_out;
136c103de24SGrant Likely 
137c103de24SGrant Likely 	/* True GPI cannot be switched to output mode */
138c103de24SGrant Likely 	if (nr < NR_VX855_GPI)
139c103de24SGrant Likely 		return;
140c103de24SGrant Likely 
141c103de24SGrant Likely 	spin_lock_irqsave(&vg->lock, flags);
142c103de24SGrant Likely 	reg_out = inl(vg->io_gpo);
143c103de24SGrant Likely 	if (nr < NR_VX855_GPInO) {
144c103de24SGrant Likely 		if (val)
145c103de24SGrant Likely 			reg_out |= gpo_o_bit(nr - NR_VX855_GPI);
146c103de24SGrant Likely 		else
147c103de24SGrant Likely 			reg_out &= ~gpo_o_bit(nr - NR_VX855_GPI);
148c103de24SGrant Likely 	} else {
149c103de24SGrant Likely 		if (val)
150c103de24SGrant Likely 			reg_out |= gpio_o_bit(nr - NR_VX855_GPInO);
151c103de24SGrant Likely 		else
152c103de24SGrant Likely 			reg_out &= ~gpio_o_bit(nr - NR_VX855_GPInO);
153c103de24SGrant Likely 	}
154c103de24SGrant Likely 	outl(reg_out, vg->io_gpo);
155c103de24SGrant Likely 	spin_unlock_irqrestore(&vg->lock, flags);
156c103de24SGrant Likely }
157c103de24SGrant Likely 
vx855gpio_direction_output(struct gpio_chip * gpio,unsigned int nr,int val)158c103de24SGrant Likely static int vx855gpio_direction_output(struct gpio_chip *gpio,
159c103de24SGrant Likely 				      unsigned int nr, int val)
160c103de24SGrant Likely {
161c103de24SGrant Likely 	/* True GPI cannot be switched to output mode */
162c103de24SGrant Likely 	if (nr < NR_VX855_GPI)
163c103de24SGrant Likely 		return -EINVAL;
164c103de24SGrant Likely 
165c103de24SGrant Likely 	/* True GPO don't need to be switched to output mode,
166c103de24SGrant Likely 	 * and GPIO are open-drain, i.e. also need no switching,
167c103de24SGrant Likely 	 * so all we do is set the level */
168c103de24SGrant Likely 	vx855gpio_set(gpio, nr, val);
169c103de24SGrant Likely 
170c103de24SGrant Likely 	return 0;
171c103de24SGrant Likely }
172c103de24SGrant Likely 
vx855gpio_set_config(struct gpio_chip * gpio,unsigned int nr,unsigned long config)1732956b5d9SMika Westerberg static int vx855gpio_set_config(struct gpio_chip *gpio, unsigned int nr,
1742956b5d9SMika Westerberg 				unsigned long config)
175640b9135SLinus Walleij {
1762956b5d9SMika Westerberg 	enum pin_config_param param = pinconf_to_config_param(config);
1772956b5d9SMika Westerberg 
178640b9135SLinus Walleij 	/* The GPI cannot be single-ended */
179640b9135SLinus Walleij 	if (nr < NR_VX855_GPI)
180640b9135SLinus Walleij 		return -EINVAL;
181640b9135SLinus Walleij 
182640b9135SLinus Walleij 	/* The GPO's are push-pull */
183640b9135SLinus Walleij 	if (nr < NR_VX855_GPInO) {
1842956b5d9SMika Westerberg 		if (param != PIN_CONFIG_DRIVE_PUSH_PULL)
185640b9135SLinus Walleij 			return -ENOTSUPP;
186640b9135SLinus Walleij 		return 0;
187640b9135SLinus Walleij 	}
188640b9135SLinus Walleij 
189640b9135SLinus Walleij 	/* The GPIO's are open drain */
1902956b5d9SMika Westerberg 	if (param != PIN_CONFIG_DRIVE_OPEN_DRAIN)
191640b9135SLinus Walleij 		return -ENOTSUPP;
192640b9135SLinus Walleij 
193640b9135SLinus Walleij 	return 0;
194640b9135SLinus Walleij }
195640b9135SLinus Walleij 
196c103de24SGrant Likely static const char *vx855gpio_names[NR_VX855_GP] = {
197c103de24SGrant Likely 	"VX855_GPI0", "VX855_GPI1", "VX855_GPI2", "VX855_GPI3", "VX855_GPI4",
198c103de24SGrant Likely 	"VX855_GPI5", "VX855_GPI6", "VX855_GPI7", "VX855_GPI8", "VX855_GPI9",
199c103de24SGrant Likely 	"VX855_GPI10", "VX855_GPI11", "VX855_GPI12", "VX855_GPI13",
200c103de24SGrant Likely 	"VX855_GPO0", "VX855_GPO1", "VX855_GPO2", "VX855_GPO3", "VX855_GPO4",
201c103de24SGrant Likely 	"VX855_GPO5", "VX855_GPO6", "VX855_GPO7", "VX855_GPO8", "VX855_GPO9",
202c103de24SGrant Likely 	"VX855_GPO10", "VX855_GPO11", "VX855_GPO12",
203c103de24SGrant Likely 	"VX855_GPIO0", "VX855_GPIO1", "VX855_GPIO2", "VX855_GPIO3",
204c103de24SGrant Likely 	"VX855_GPIO4", "VX855_GPIO5", "VX855_GPIO6", "VX855_GPIO7",
205c103de24SGrant Likely 	"VX855_GPIO8", "VX855_GPIO9", "VX855_GPIO10", "VX855_GPIO11",
206c103de24SGrant Likely 	"VX855_GPIO12", "VX855_GPIO13", "VX855_GPIO14"
207c103de24SGrant Likely };
208c103de24SGrant Likely 
vx855gpio_gpio_setup(struct vx855_gpio * vg)209c103de24SGrant Likely static void vx855gpio_gpio_setup(struct vx855_gpio *vg)
210c103de24SGrant Likely {
211c103de24SGrant Likely 	struct gpio_chip *c = &vg->gpio;
212c103de24SGrant Likely 
213c103de24SGrant Likely 	c->label = "VX855 South Bridge";
214c103de24SGrant Likely 	c->owner = THIS_MODULE;
215c103de24SGrant Likely 	c->direction_input = vx855gpio_direction_input;
216c103de24SGrant Likely 	c->direction_output = vx855gpio_direction_output;
217c103de24SGrant Likely 	c->get = vx855gpio_get;
218c103de24SGrant Likely 	c->set = vx855gpio_set;
219*10c942a1SZheng Yongjun 	c->set_config = vx855gpio_set_config;
220c103de24SGrant Likely 	c->dbg_show = NULL;
221c103de24SGrant Likely 	c->base = 0;
222c103de24SGrant Likely 	c->ngpio = NR_VX855_GP;
2239fb1f39eSLinus Walleij 	c->can_sleep = false;
224c103de24SGrant Likely 	c->names = vx855gpio_names;
225c103de24SGrant Likely }
226c103de24SGrant Likely 
227c103de24SGrant Likely /* This platform device is ordinarily registered by the vx855 mfd driver */
vx855gpio_probe(struct platform_device * pdev)2283836309dSBill Pemberton static int vx855gpio_probe(struct platform_device *pdev)
229c103de24SGrant Likely {
230c103de24SGrant Likely 	struct resource *res_gpi;
231c103de24SGrant Likely 	struct resource *res_gpo;
232c103de24SGrant Likely 	struct vx855_gpio *vg;
233c103de24SGrant Likely 
234c103de24SGrant Likely 	res_gpi = platform_get_resource(pdev, IORESOURCE_IO, 0);
235c103de24SGrant Likely 	res_gpo = platform_get_resource(pdev, IORESOURCE_IO, 1);
236c103de24SGrant Likely 	if (!res_gpi || !res_gpo)
237c103de24SGrant Likely 		return -EBUSY;
238c103de24SGrant Likely 
2395b6a342bSAxel Lin 	vg = devm_kzalloc(&pdev->dev, sizeof(*vg), GFP_KERNEL);
240c103de24SGrant Likely 	if (!vg)
241c103de24SGrant Likely 		return -ENOMEM;
242c103de24SGrant Likely 
243c103de24SGrant Likely 	dev_info(&pdev->dev, "found VX855 GPIO controller\n");
244c103de24SGrant Likely 	vg->io_gpi = res_gpi->start;
245c103de24SGrant Likely 	vg->io_gpo = res_gpo->start;
246c103de24SGrant Likely 	spin_lock_init(&vg->lock);
247c103de24SGrant Likely 
248c103de24SGrant Likely 	/*
249c103de24SGrant Likely 	 * A single byte is used to control various GPIO ports on the VX855,
250c103de24SGrant Likely 	 * and in the case of the OLPC XO-1.5, some of those ports are used
251c103de24SGrant Likely 	 * for switches that are interpreted and exposed through ACPI. ACPI
252c103de24SGrant Likely 	 * will have reserved the region, so our own reservation will not
253c103de24SGrant Likely 	 * succeed. Ignore and continue.
254c103de24SGrant Likely 	 */
255c103de24SGrant Likely 
2565b6a342bSAxel Lin 	if (!devm_request_region(&pdev->dev, res_gpi->start,
2575b6a342bSAxel Lin 				 resource_size(res_gpi), MODULE_NAME "_gpi"))
258c103de24SGrant Likely 		dev_warn(&pdev->dev,
259c103de24SGrant Likely 			"GPI I/O resource busy, probably claimed by ACPI\n");
260c103de24SGrant Likely 
2615b6a342bSAxel Lin 	if (!devm_request_region(&pdev->dev, res_gpo->start,
2625b6a342bSAxel Lin 				 resource_size(res_gpo), MODULE_NAME "_gpo"))
263c103de24SGrant Likely 		dev_warn(&pdev->dev,
264c103de24SGrant Likely 			"GPO I/O resource busy, probably claimed by ACPI\n");
265c103de24SGrant Likely 
266c103de24SGrant Likely 	vx855gpio_gpio_setup(vg);
267c103de24SGrant Likely 
26855e3e1a7SLaxman Dewangan 	return devm_gpiochip_add_data(&pdev->dev, &vg->gpio, vg);
269c103de24SGrant Likely }
270c103de24SGrant Likely 
271c103de24SGrant Likely static struct platform_driver vx855gpio_driver = {
272c103de24SGrant Likely 	.driver = {
273c103de24SGrant Likely 		.name	= MODULE_NAME,
274c103de24SGrant Likely 	},
275c103de24SGrant Likely 	.probe		= vx855gpio_probe,
276c103de24SGrant Likely };
277c103de24SGrant Likely 
2786f61415eSMark Brown module_platform_driver(vx855gpio_driver);
279c103de24SGrant Likely 
280c103de24SGrant Likely MODULE_LICENSE("GPL");
281c103de24SGrant Likely MODULE_AUTHOR("Harald Welte <HaraldWelte@viatech.com>");
282c103de24SGrant Likely MODULE_DESCRIPTION("GPIO driver for the VIA VX855 chipset");
283c103de24SGrant Likely MODULE_ALIAS("platform:vx855_gpio");
284