1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
8 #include <linux/kernel.h>
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/types.h>
12 #include <linux/gpio/consumer.h>
13 #include <linux/gpio/driver.h>
14 #include <linux/platform_device.h>
15 #include <linux/of_platform.h>
16 #include <linux/of_gpio.h>
18 #define GPIO_LATCH_DRIVER_NAME "gpio-latch"
19 #define GPIO_LATCH_LINES 9
21 struct gpio_latch_chip
{
24 struct mutex latch_mutex
;
28 struct gpio_desc
*gpios
[GPIO_LATCH_LINES
];
31 static inline struct gpio_latch_chip
*to_gpio_latch_chip(struct gpio_chip
*gc
)
33 return container_of(gc
, struct gpio_latch_chip
, gc
);
36 static void gpio_latch_lock(struct gpio_latch_chip
*glc
, bool enable
)
38 mutex_lock(&glc
->mutex
);
41 glc
->latch_enabled
= true;
43 if (glc
->latch_enabled
)
44 mutex_lock(&glc
->latch_mutex
);
47 static void gpio_latch_unlock(struct gpio_latch_chip
*glc
, bool disable
)
49 if (glc
->latch_enabled
)
50 mutex_unlock(&glc
->latch_mutex
);
53 glc
->latch_enabled
= true;
55 mutex_unlock(&glc
->mutex
);
59 gpio_latch_get(struct gpio_chip
*gc
, unsigned offset
)
61 struct gpio_latch_chip
*glc
= to_gpio_latch_chip(gc
);
64 gpio_latch_lock(glc
, false);
65 ret
= gpiod_get_raw_value_cansleep(glc
->gpios
[offset
]);
66 gpio_latch_unlock(glc
, false);
72 gpio_latch_set(struct gpio_chip
*gc
, unsigned offset
, int value
)
74 struct gpio_latch_chip
*glc
= to_gpio_latch_chip(gc
);
75 bool enable_latch
= false;
76 bool disable_latch
= false;
78 if (offset
== glc
->le_gpio
) {
79 enable_latch
= value
^ glc
->le_active_low
;
80 disable_latch
= !enable_latch
;
83 gpio_latch_lock(glc
, enable_latch
);
84 gpiod_set_raw_value_cansleep(glc
->gpios
[offset
], value
);
85 gpio_latch_unlock(glc
, disable_latch
);
89 gpio_latch_direction_output(struct gpio_chip
*gc
, unsigned offset
, int value
)
91 struct gpio_latch_chip
*glc
= to_gpio_latch_chip(gc
);
92 bool enable_latch
= false;
93 bool disable_latch
= false;
96 if (offset
== glc
->le_gpio
) {
97 enable_latch
= value
^ glc
->le_active_low
;
98 disable_latch
= !enable_latch
;
101 gpio_latch_lock(glc
, enable_latch
);
102 ret
= gpiod_direction_output_raw(glc
->gpios
[offset
], value
);
103 gpio_latch_unlock(glc
, disable_latch
);
108 static int gpio_latch_probe(struct platform_device
*pdev
)
110 struct gpio_latch_chip
*glc
;
111 struct gpio_chip
*gc
;
112 struct device
*dev
= &pdev
->dev
;
113 struct device_node
*of_node
= dev
->of_node
;
116 glc
= devm_kzalloc(dev
, sizeof(*glc
), GFP_KERNEL
);
120 mutex_init(&glc
->mutex
);
121 mutex_init(&glc
->latch_mutex
);
123 n
= gpiod_count(dev
, NULL
);
125 dev_err(dev
, "failed to get gpios: %d\n", n
);
127 } else if (n
!= GPIO_LATCH_LINES
) {
128 dev_err(dev
, "expected %d gpios\n", GPIO_LATCH_LINES
);
132 for (i
= 0; i
< n
; i
++) {
133 glc
->gpios
[i
] = devm_gpiod_get_index_optional(dev
, NULL
, i
,
135 if (IS_ERR(glc
->gpios
[i
])) {
136 if (PTR_ERR(glc
->gpios
[i
]) != -EPROBE_DEFER
) {
137 dev_err(dev
, "failed to get gpio %d: %ld\n", i
,
138 PTR_ERR(glc
->gpios
[i
]));
140 return PTR_ERR(glc
->gpios
[i
]);
145 glc
->le_active_low
= gpiod_is_active_low(glc
->gpios
[glc
->le_gpio
]);
147 if (!glc
->gpios
[glc
->le_gpio
]) {
148 dev_err(dev
, "missing required latch-enable gpio %d\n",
154 gc
->label
= GPIO_LATCH_DRIVER_NAME
;
155 gc
->can_sleep
= true;
157 gc
->ngpio
= GPIO_LATCH_LINES
;
158 gc
->get
= gpio_latch_get
;
159 gc
->set
= gpio_latch_set
;
160 gc
->direction_output
= gpio_latch_direction_output
;
161 gc
->of_node
= of_node
;
163 platform_set_drvdata(pdev
, glc
);
165 i
= gpiochip_add(&glc
->gc
);
167 dev_err(dev
, "gpiochip_add() failed: %d\n", i
);
174 static int gpio_latch_remove(struct platform_device
*pdev
)
176 struct gpio_latch_chip
*glc
= platform_get_drvdata(pdev
);
178 gpiochip_remove(&glc
->gc
);
182 static const struct of_device_id gpio_latch_match
[] = {
183 { .compatible
= GPIO_LATCH_DRIVER_NAME
},
187 MODULE_DEVICE_TABLE(of
, gpio_latch_match
);
189 static struct platform_driver gpio_latch_driver
= {
190 .probe
= gpio_latch_probe
,
191 .remove
= gpio_latch_remove
,
193 .name
= GPIO_LATCH_DRIVER_NAME
,
194 .owner
= THIS_MODULE
,
195 .of_match_table
= gpio_latch_match
,
199 module_platform_driver(gpio_latch_driver
);
201 MODULE_DESCRIPTION("GPIO latch driver");
202 MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
203 MODULE_AUTHOR("Denis Kalashnikov <denis281089@gmail.com>");
204 MODULE_LICENSE("GPL v2");
205 MODULE_ALIAS("platform:" GPIO_LATCH_DRIVER_NAME
);