1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2015-2017 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
6 #include <linux/gpio/consumer.h>
7 #include <linux/module.h>
8 #include <linux/platform_device.h>
10 #include <linux/delay.h>
14 #define DRIVER_NAME "siox-gpio"
16 struct siox_gpio_ddata
{
17 struct gpio_desc
*din
;
18 struct gpio_desc
*dout
;
19 struct gpio_desc
*dclk
;
20 struct gpio_desc
*dld
;
23 static unsigned int siox_clkhigh_ns
= 1000;
24 static unsigned int siox_loadhigh_ns
;
25 static unsigned int siox_bytegap_ns
;
27 static int siox_gpio_pushpull(struct siox_master
*smaster
,
28 size_t setbuf_len
, const u8 setbuf
[],
29 size_t getbuf_len
, u8 getbuf
[])
31 struct siox_gpio_ddata
*ddata
= siox_master_get_devdata(smaster
);
33 size_t cycles
= max(setbuf_len
, getbuf_len
);
35 /* reset data and clock */
36 gpiod_set_value_cansleep(ddata
->dout
, 0);
37 gpiod_set_value_cansleep(ddata
->dclk
, 0);
39 gpiod_set_value_cansleep(ddata
->dld
, 1);
40 ndelay(siox_loadhigh_ns
);
41 gpiod_set_value_cansleep(ddata
->dld
, 0);
43 for (i
= 0; i
< cycles
; ++i
) {
47 if (i
>= cycles
- setbuf_len
)
48 set
= setbuf
[i
- (cycles
- setbuf_len
)];
50 for (j
= 0; j
< 8; ++j
) {
52 if (gpiod_get_value_cansleep(ddata
->din
))
55 /* DOUT is logically inverted */
56 gpiod_set_value_cansleep(ddata
->dout
, !(set
& 0x80));
59 gpiod_set_value_cansleep(ddata
->dclk
, 1);
60 ndelay(siox_clkhigh_ns
);
61 gpiod_set_value_cansleep(ddata
->dclk
, 0);
67 ndelay(siox_bytegap_ns
);
70 gpiod_set_value_cansleep(ddata
->dld
, 1);
71 ndelay(siox_loadhigh_ns
);
72 gpiod_set_value_cansleep(ddata
->dld
, 0);
75 * Resetting dout isn't necessary protocol wise, but it makes the
76 * signals more pretty because the dout level is deterministic between
77 * cycles. Note that this only affects dout between the master and the
78 * first siox device. dout for the later devices depend on the output of
79 * the previous siox device.
81 gpiod_set_value_cansleep(ddata
->dout
, 0);
86 static int siox_gpio_probe(struct platform_device
*pdev
)
88 struct device
*dev
= &pdev
->dev
;
89 struct siox_gpio_ddata
*ddata
;
91 struct siox_master
*smaster
;
93 smaster
= siox_master_alloc(&pdev
->dev
, sizeof(*ddata
));
95 dev_err(dev
, "failed to allocate siox master\n");
99 platform_set_drvdata(pdev
, smaster
);
100 ddata
= siox_master_get_devdata(smaster
);
102 ddata
->din
= devm_gpiod_get(dev
, "din", GPIOD_IN
);
103 if (IS_ERR(ddata
->din
)) {
104 ret
= PTR_ERR(ddata
->din
);
105 dev_err(dev
, "Failed to get %s GPIO: %d\n", "din", ret
);
109 ddata
->dout
= devm_gpiod_get(dev
, "dout", GPIOD_OUT_LOW
);
110 if (IS_ERR(ddata
->dout
)) {
111 ret
= PTR_ERR(ddata
->dout
);
112 dev_err(dev
, "Failed to get %s GPIO: %d\n", "dout", ret
);
116 ddata
->dclk
= devm_gpiod_get(dev
, "dclk", GPIOD_OUT_LOW
);
117 if (IS_ERR(ddata
->dclk
)) {
118 ret
= PTR_ERR(ddata
->dclk
);
119 dev_err(dev
, "Failed to get %s GPIO: %d\n", "dclk", ret
);
123 ddata
->dld
= devm_gpiod_get(dev
, "dld", GPIOD_OUT_LOW
);
124 if (IS_ERR(ddata
->dld
)) {
125 ret
= PTR_ERR(ddata
->dld
);
126 dev_err(dev
, "Failed to get %s GPIO: %d\n", "dld", ret
);
130 smaster
->pushpull
= siox_gpio_pushpull
;
131 /* XXX: determine automatically like spi does */
134 ret
= siox_master_register(smaster
);
136 dev_err(dev
, "Failed to register siox master: %d\n", ret
);
138 siox_master_put(smaster
);
144 static int siox_gpio_remove(struct platform_device
*pdev
)
146 struct siox_master
*master
= platform_get_drvdata(pdev
);
148 siox_master_unregister(master
);
153 static const struct of_device_id siox_gpio_dt_ids
[] = {
154 { .compatible
= "eckelmann,siox-gpio", },
157 MODULE_DEVICE_TABLE(of
, siox_gpio_dt_ids
);
159 static struct platform_driver siox_gpio_driver
= {
160 .probe
= siox_gpio_probe
,
161 .remove
= siox_gpio_remove
,
165 .of_match_table
= siox_gpio_dt_ids
,
168 module_platform_driver(siox_gpio_driver
);
170 MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
171 MODULE_LICENSE("GPL v2");
172 MODULE_ALIAS("platform:" DRIVER_NAME
);