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