1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Congatec Board Controller GPIO driver
5 * Copyright (C) 2024 Bootlin
6 * Author: Thomas Richard <thomas.richard@bootlin.com>
9 #include <linux/gpio/driver.h>
10 #include <linux/mfd/cgbc.h>
11 #include <linux/module.h>
12 #include <linux/mutex.h>
13 #include <linux/platform_device.h>
15 #define CGBC_GPIO_NGPIO 14
17 #define CGBC_GPIO_CMD_GET 0x64
18 #define CGBC_GPIO_CMD_SET 0x65
19 #define CGBC_GPIO_CMD_DIR_GET 0x66
20 #define CGBC_GPIO_CMD_DIR_SET 0x67
22 struct cgbc_gpio_data
{
23 struct gpio_chip chip
;
24 struct cgbc_device_data
*cgbc
;
28 static int cgbc_gpio_cmd(struct cgbc_device_data
*cgbc
,
29 u8 cmd0
, u8 cmd1
, u8 cmd2
, u8
*value
)
31 u8 cmd
[3] = {cmd0
, cmd1
, cmd2
};
33 return cgbc_command(cgbc
, cmd
, sizeof(cmd
), value
, 1, NULL
);
36 static int cgbc_gpio_get(struct gpio_chip
*chip
, unsigned int offset
)
38 struct cgbc_gpio_data
*gpio
= gpiochip_get_data(chip
);
39 struct cgbc_device_data
*cgbc
= gpio
->cgbc
;
43 scoped_guard(mutex
, &gpio
->lock
)
44 ret
= cgbc_gpio_cmd(cgbc
, CGBC_GPIO_CMD_GET
, (offset
> 7) ? 1 : 0, 0, &val
);
51 return (int)(val
& (u8
)BIT(offset
));
54 static void __cgbc_gpio_set(struct gpio_chip
*chip
,
55 unsigned int offset
, int value
)
57 struct cgbc_gpio_data
*gpio
= gpiochip_get_data(chip
);
58 struct cgbc_device_data
*cgbc
= gpio
->cgbc
;
62 ret
= cgbc_gpio_cmd(cgbc
, CGBC_GPIO_CMD_GET
, (offset
> 7) ? 1 : 0, 0, &val
);
67 val
|= BIT(offset
% 8);
69 val
&= ~(BIT(offset
% 8));
71 cgbc_gpio_cmd(cgbc
, CGBC_GPIO_CMD_SET
, (offset
> 7) ? 1 : 0, val
, &val
);
74 static void cgbc_gpio_set(struct gpio_chip
*chip
,
75 unsigned int offset
, int value
)
77 struct cgbc_gpio_data
*gpio
= gpiochip_get_data(chip
);
79 scoped_guard(mutex
, &gpio
->lock
)
80 __cgbc_gpio_set(chip
, offset
, value
);
83 static int cgbc_gpio_direction_set(struct gpio_chip
*chip
,
84 unsigned int offset
, int direction
)
86 struct cgbc_gpio_data
*gpio
= gpiochip_get_data(chip
);
87 struct cgbc_device_data
*cgbc
= gpio
->cgbc
;
91 ret
= cgbc_gpio_cmd(cgbc
, CGBC_GPIO_CMD_DIR_GET
, (offset
> 7) ? 1 : 0, 0, &val
);
95 if (direction
== GPIO_LINE_DIRECTION_IN
)
96 val
&= ~(BIT(offset
% 8));
98 val
|= BIT(offset
% 8);
100 ret
= cgbc_gpio_cmd(cgbc
, CGBC_GPIO_CMD_DIR_SET
, (offset
> 7) ? 1 : 0, val
, &val
);
106 static int cgbc_gpio_direction_input(struct gpio_chip
*chip
,
109 struct cgbc_gpio_data
*gpio
= gpiochip_get_data(chip
);
111 guard(mutex
)(&gpio
->lock
);
112 return cgbc_gpio_direction_set(chip
, offset
, GPIO_LINE_DIRECTION_IN
);
115 static int cgbc_gpio_direction_output(struct gpio_chip
*chip
,
116 unsigned int offset
, int value
)
118 struct cgbc_gpio_data
*gpio
= gpiochip_get_data(chip
);
120 guard(mutex
)(&gpio
->lock
);
122 __cgbc_gpio_set(chip
, offset
, value
);
123 return cgbc_gpio_direction_set(chip
, offset
, GPIO_LINE_DIRECTION_OUT
);
126 static int cgbc_gpio_get_direction(struct gpio_chip
*chip
, unsigned int offset
)
128 struct cgbc_gpio_data
*gpio
= gpiochip_get_data(chip
);
129 struct cgbc_device_data
*cgbc
= gpio
->cgbc
;
133 scoped_guard(mutex
, &gpio
->lock
)
134 ret
= cgbc_gpio_cmd(cgbc
, CGBC_GPIO_CMD_DIR_GET
, (offset
> 7) ? 1 : 0, 0, &val
);
139 if (val
& BIT(offset
% 8))
140 return GPIO_LINE_DIRECTION_OUT
;
142 return GPIO_LINE_DIRECTION_IN
;
145 static int cgbc_gpio_probe(struct platform_device
*pdev
)
147 struct device
*dev
= &pdev
->dev
;
148 struct cgbc_device_data
*cgbc
= dev_get_drvdata(dev
->parent
);
149 struct cgbc_gpio_data
*gpio
;
150 struct gpio_chip
*chip
;
153 gpio
= devm_kzalloc(dev
, sizeof(*gpio
), GFP_KERNEL
);
159 platform_set_drvdata(pdev
, gpio
);
162 chip
->label
= dev_name(&pdev
->dev
);
163 chip
->owner
= THIS_MODULE
;
166 chip
->direction_input
= cgbc_gpio_direction_input
;
167 chip
->direction_output
= cgbc_gpio_direction_output
;
168 chip
->get_direction
= cgbc_gpio_get_direction
;
169 chip
->get
= cgbc_gpio_get
;
170 chip
->set
= cgbc_gpio_set
;
171 chip
->ngpio
= CGBC_GPIO_NGPIO
;
173 ret
= devm_mutex_init(dev
, &gpio
->lock
);
177 ret
= devm_gpiochip_add_data(dev
, chip
, gpio
);
179 return dev_err_probe(dev
, ret
, "Could not register GPIO chip\n");
184 static struct platform_driver cgbc_gpio_driver
= {
188 .probe
= cgbc_gpio_probe
,
191 module_platform_driver(cgbc_gpio_driver
);
193 MODULE_DESCRIPTION("Congatec Board Controller GPIO Driver");
194 MODULE_AUTHOR("Thomas Richard <thomas.richard@bootlin.com>");
195 MODULE_LICENSE("GPL");
196 MODULE_ALIAS("platform:cgbc-gpio");