xref: /openbmc/linux/drivers/gpio/gpio-en7523.c (revision 0868ad38)
1*0868ad38SJohn Crispin // SPDX-License-Identifier: GPL-2.0-only
2*0868ad38SJohn Crispin 
3*0868ad38SJohn Crispin #include <linux/types.h>
4*0868ad38SJohn Crispin #include <linux/io.h>
5*0868ad38SJohn Crispin #include <linux/bits.h>
6*0868ad38SJohn Crispin #include <linux/gpio/driver.h>
7*0868ad38SJohn Crispin #include <linux/mod_devicetable.h>
8*0868ad38SJohn Crispin #include <linux/module.h>
9*0868ad38SJohn Crispin #include <linux/platform_device.h>
10*0868ad38SJohn Crispin #include <linux/property.h>
11*0868ad38SJohn Crispin 
12*0868ad38SJohn Crispin #define AIROHA_GPIO_MAX		32
13*0868ad38SJohn Crispin 
14*0868ad38SJohn Crispin /**
15*0868ad38SJohn Crispin  * airoha_gpio_ctrl - Airoha GPIO driver data
16*0868ad38SJohn Crispin  * @gc: Associated gpio_chip instance.
17*0868ad38SJohn Crispin  * @data: The data register.
18*0868ad38SJohn Crispin  * @dir0: The direction register for the lower 16 pins.
19*0868ad38SJohn Crispin  * @dir1: The direction register for the higher 16 pins.
20*0868ad38SJohn Crispin  * @output: The output enable register.
21*0868ad38SJohn Crispin  */
22*0868ad38SJohn Crispin struct airoha_gpio_ctrl {
23*0868ad38SJohn Crispin 	struct gpio_chip gc;
24*0868ad38SJohn Crispin 	void __iomem *data;
25*0868ad38SJohn Crispin 	void __iomem *dir[2];
26*0868ad38SJohn Crispin 	void __iomem *output;
27*0868ad38SJohn Crispin };
28*0868ad38SJohn Crispin 
gc_to_ctrl(struct gpio_chip * gc)29*0868ad38SJohn Crispin static struct airoha_gpio_ctrl *gc_to_ctrl(struct gpio_chip *gc)
30*0868ad38SJohn Crispin {
31*0868ad38SJohn Crispin 	return container_of(gc, struct airoha_gpio_ctrl, gc);
32*0868ad38SJohn Crispin }
33*0868ad38SJohn Crispin 
airoha_dir_set(struct gpio_chip * gc,unsigned int gpio,int val,int out)34*0868ad38SJohn Crispin static int airoha_dir_set(struct gpio_chip *gc, unsigned int gpio,
35*0868ad38SJohn Crispin 			  int val, int out)
36*0868ad38SJohn Crispin {
37*0868ad38SJohn Crispin 	struct airoha_gpio_ctrl *ctrl = gc_to_ctrl(gc);
38*0868ad38SJohn Crispin 	u32 dir = ioread32(ctrl->dir[gpio / 16]);
39*0868ad38SJohn Crispin 	u32 output = ioread32(ctrl->output);
40*0868ad38SJohn Crispin 	u32 mask = BIT((gpio % 16) * 2);
41*0868ad38SJohn Crispin 
42*0868ad38SJohn Crispin 	if (out) {
43*0868ad38SJohn Crispin 		dir |= mask;
44*0868ad38SJohn Crispin 		output |= BIT(gpio);
45*0868ad38SJohn Crispin 	} else {
46*0868ad38SJohn Crispin 		dir &= ~mask;
47*0868ad38SJohn Crispin 		output &= ~BIT(gpio);
48*0868ad38SJohn Crispin 	}
49*0868ad38SJohn Crispin 
50*0868ad38SJohn Crispin 	iowrite32(dir, ctrl->dir[gpio / 16]);
51*0868ad38SJohn Crispin 
52*0868ad38SJohn Crispin 	if (out)
53*0868ad38SJohn Crispin 		gc->set(gc, gpio, val);
54*0868ad38SJohn Crispin 
55*0868ad38SJohn Crispin 	iowrite32(output, ctrl->output);
56*0868ad38SJohn Crispin 
57*0868ad38SJohn Crispin 	return 0;
58*0868ad38SJohn Crispin }
59*0868ad38SJohn Crispin 
airoha_dir_out(struct gpio_chip * gc,unsigned int gpio,int val)60*0868ad38SJohn Crispin static int airoha_dir_out(struct gpio_chip *gc, unsigned int gpio,
61*0868ad38SJohn Crispin 			  int val)
62*0868ad38SJohn Crispin {
63*0868ad38SJohn Crispin 	return airoha_dir_set(gc, gpio, val, 1);
64*0868ad38SJohn Crispin }
65*0868ad38SJohn Crispin 
airoha_dir_in(struct gpio_chip * gc,unsigned int gpio)66*0868ad38SJohn Crispin static int airoha_dir_in(struct gpio_chip *gc, unsigned int gpio)
67*0868ad38SJohn Crispin {
68*0868ad38SJohn Crispin 	return airoha_dir_set(gc, gpio, 0, 0);
69*0868ad38SJohn Crispin }
70*0868ad38SJohn Crispin 
airoha_get_dir(struct gpio_chip * gc,unsigned int gpio)71*0868ad38SJohn Crispin static int airoha_get_dir(struct gpio_chip *gc, unsigned int gpio)
72*0868ad38SJohn Crispin {
73*0868ad38SJohn Crispin 	struct airoha_gpio_ctrl *ctrl = gc_to_ctrl(gc);
74*0868ad38SJohn Crispin 	u32 dir = ioread32(ctrl->dir[gpio / 16]);
75*0868ad38SJohn Crispin 	u32 mask = BIT((gpio % 16) * 2);
76*0868ad38SJohn Crispin 
77*0868ad38SJohn Crispin 	return (dir & mask) ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
78*0868ad38SJohn Crispin }
79*0868ad38SJohn Crispin 
airoha_gpio_probe(struct platform_device * pdev)80*0868ad38SJohn Crispin static int airoha_gpio_probe(struct platform_device *pdev)
81*0868ad38SJohn Crispin {
82*0868ad38SJohn Crispin 	struct device *dev = &pdev->dev;
83*0868ad38SJohn Crispin 	struct airoha_gpio_ctrl *ctrl;
84*0868ad38SJohn Crispin 	int err;
85*0868ad38SJohn Crispin 
86*0868ad38SJohn Crispin 	ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
87*0868ad38SJohn Crispin 	if (!ctrl)
88*0868ad38SJohn Crispin 		return -ENOMEM;
89*0868ad38SJohn Crispin 
90*0868ad38SJohn Crispin 	ctrl->data = devm_platform_ioremap_resource(pdev, 0);
91*0868ad38SJohn Crispin 	if (IS_ERR(ctrl->data))
92*0868ad38SJohn Crispin 		return PTR_ERR(ctrl->data);
93*0868ad38SJohn Crispin 
94*0868ad38SJohn Crispin 	ctrl->dir[0] = devm_platform_ioremap_resource(pdev, 1);
95*0868ad38SJohn Crispin 	if (IS_ERR(ctrl->dir[0]))
96*0868ad38SJohn Crispin 		return PTR_ERR(ctrl->dir[0]);
97*0868ad38SJohn Crispin 
98*0868ad38SJohn Crispin 	ctrl->dir[1] = devm_platform_ioremap_resource(pdev, 2);
99*0868ad38SJohn Crispin 	if (IS_ERR(ctrl->dir[1]))
100*0868ad38SJohn Crispin 		return PTR_ERR(ctrl->dir[1]);
101*0868ad38SJohn Crispin 
102*0868ad38SJohn Crispin 	ctrl->output = devm_platform_ioremap_resource(pdev, 3);
103*0868ad38SJohn Crispin 	if (IS_ERR(ctrl->output))
104*0868ad38SJohn Crispin 		return PTR_ERR(ctrl->output);
105*0868ad38SJohn Crispin 
106*0868ad38SJohn Crispin 	err = bgpio_init(&ctrl->gc, dev, 4, ctrl->data, NULL,
107*0868ad38SJohn Crispin 			 NULL, NULL, NULL, 0);
108*0868ad38SJohn Crispin 	if (err)
109*0868ad38SJohn Crispin 		return dev_err_probe(dev, err, "unable to init generic GPIO");
110*0868ad38SJohn Crispin 
111*0868ad38SJohn Crispin 	ctrl->gc.ngpio = AIROHA_GPIO_MAX;
112*0868ad38SJohn Crispin 	ctrl->gc.owner = THIS_MODULE;
113*0868ad38SJohn Crispin 	ctrl->gc.direction_output = airoha_dir_out;
114*0868ad38SJohn Crispin 	ctrl->gc.direction_input = airoha_dir_in;
115*0868ad38SJohn Crispin 	ctrl->gc.get_direction = airoha_get_dir;
116*0868ad38SJohn Crispin 
117*0868ad38SJohn Crispin 	return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
118*0868ad38SJohn Crispin }
119*0868ad38SJohn Crispin 
120*0868ad38SJohn Crispin static const struct of_device_id airoha_gpio_of_match[] = {
121*0868ad38SJohn Crispin 	{ .compatible = "airoha,en7523-gpio" },
122*0868ad38SJohn Crispin 	{ }
123*0868ad38SJohn Crispin };
124*0868ad38SJohn Crispin MODULE_DEVICE_TABLE(of, airoha_gpio_of_match);
125*0868ad38SJohn Crispin 
126*0868ad38SJohn Crispin static struct platform_driver airoha_gpio_driver = {
127*0868ad38SJohn Crispin 	.driver = {
128*0868ad38SJohn Crispin 		.name = "airoha-gpio",
129*0868ad38SJohn Crispin 		.of_match_table	= airoha_gpio_of_match,
130*0868ad38SJohn Crispin 	},
131*0868ad38SJohn Crispin 	.probe = airoha_gpio_probe,
132*0868ad38SJohn Crispin };
133*0868ad38SJohn Crispin module_platform_driver(airoha_gpio_driver);
134*0868ad38SJohn Crispin 
135*0868ad38SJohn Crispin MODULE_DESCRIPTION("Airoha GPIO support");
136*0868ad38SJohn Crispin MODULE_AUTHOR("John Crispin <john@phrozen.org>");
137*0868ad38SJohn Crispin MODULE_LICENSE("GPL v2");
138