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/mod_devicetable.h>
9 #include <linux/platform_device.h>
11 #include <linux/delay.h>
15 #define DRIVER_NAME "siox-gpio"
17 struct siox_gpio_ddata
{
18 struct gpio_desc
*din
;
19 struct gpio_desc
*dout
;
20 struct gpio_desc
*dclk
;
21 struct gpio_desc
*dld
;
24 static unsigned int siox_clkhigh_ns
= 1000;
25 static unsigned int siox_loadhigh_ns
;
26 static unsigned int siox_bytegap_ns
;
28 static int siox_gpio_pushpull(struct siox_master
*smaster
,
29 size_t setbuf_len
, const u8 setbuf
[],
30 size_t getbuf_len
, u8 getbuf
[])
32 struct siox_gpio_ddata
*ddata
= siox_master_get_devdata(smaster
);
34 size_t cycles
= max(setbuf_len
, getbuf_len
);
36 /* reset data and clock */
37 gpiod_set_value_cansleep(ddata
->dout
, 0);
38 gpiod_set_value_cansleep(ddata
->dclk
, 0);
40 gpiod_set_value_cansleep(ddata
->dld
, 1);
41 ndelay(siox_loadhigh_ns
);
42 gpiod_set_value_cansleep(ddata
->dld
, 0);
44 for (i
= 0; i
< cycles
; ++i
) {
48 if (i
>= cycles
- setbuf_len
)
49 set
= setbuf
[i
- (cycles
- setbuf_len
)];
51 for (j
= 0; j
< 8; ++j
) {
53 if (gpiod_get_value_cansleep(ddata
->din
))
56 /* DOUT is logically inverted */
57 gpiod_set_value_cansleep(ddata
->dout
, !(set
& 0x80));
60 gpiod_set_value_cansleep(ddata
->dclk
, 1);
61 ndelay(siox_clkhigh_ns
);
62 gpiod_set_value_cansleep(ddata
->dclk
, 0);
68 ndelay(siox_bytegap_ns
);
71 gpiod_set_value_cansleep(ddata
->dld
, 1);
72 ndelay(siox_loadhigh_ns
);
73 gpiod_set_value_cansleep(ddata
->dld
, 0);
76 * Resetting dout isn't necessary protocol wise, but it makes the
77 * signals more pretty because the dout level is deterministic between
78 * cycles. Note that this only affects dout between the master and the
79 * first siox device. dout for the later devices depend on the output of
80 * the previous siox device.
82 gpiod_set_value_cansleep(ddata
->dout
, 0);
87 static int siox_gpio_probe(struct platform_device
*pdev
)
89 struct device
*dev
= &pdev
->dev
;
90 struct siox_gpio_ddata
*ddata
;
92 struct siox_master
*smaster
;
94 smaster
= siox_master_alloc(&pdev
->dev
, sizeof(*ddata
));
96 dev_err(dev
, "failed to allocate siox master\n");
100 platform_set_drvdata(pdev
, smaster
);
101 ddata
= siox_master_get_devdata(smaster
);
103 ddata
->din
= devm_gpiod_get(dev
, "din", GPIOD_IN
);
104 if (IS_ERR(ddata
->din
)) {
105 ret
= PTR_ERR(ddata
->din
);
106 dev_err(dev
, "Failed to get %s GPIO: %d\n", "din", ret
);
110 ddata
->dout
= devm_gpiod_get(dev
, "dout", GPIOD_OUT_LOW
);
111 if (IS_ERR(ddata
->dout
)) {
112 ret
= PTR_ERR(ddata
->dout
);
113 dev_err(dev
, "Failed to get %s GPIO: %d\n", "dout", ret
);
117 ddata
->dclk
= devm_gpiod_get(dev
, "dclk", GPIOD_OUT_LOW
);
118 if (IS_ERR(ddata
->dclk
)) {
119 ret
= PTR_ERR(ddata
->dclk
);
120 dev_err(dev
, "Failed to get %s GPIO: %d\n", "dclk", ret
);
124 ddata
->dld
= devm_gpiod_get(dev
, "dld", GPIOD_OUT_LOW
);
125 if (IS_ERR(ddata
->dld
)) {
126 ret
= PTR_ERR(ddata
->dld
);
127 dev_err(dev
, "Failed to get %s GPIO: %d\n", "dld", ret
);
131 smaster
->pushpull
= siox_gpio_pushpull
;
132 /* XXX: determine automatically like spi does */
135 ret
= siox_master_register(smaster
);
137 dev_err(dev
, "Failed to register siox master: %d\n", ret
);
139 siox_master_put(smaster
);
145 static int siox_gpio_remove(struct platform_device
*pdev
)
147 struct siox_master
*master
= platform_get_drvdata(pdev
);
149 siox_master_unregister(master
);
154 static const struct of_device_id siox_gpio_dt_ids
[] = {
155 { .compatible
= "eckelmann,siox-gpio", },
158 MODULE_DEVICE_TABLE(of
, siox_gpio_dt_ids
);
160 static struct platform_driver siox_gpio_driver
= {
161 .probe
= siox_gpio_probe
,
162 .remove
= siox_gpio_remove
,
166 .of_match_table
= siox_gpio_dt_ids
,
169 module_platform_driver(siox_gpio_driver
);
171 MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
172 MODULE_LICENSE("GPL v2");
173 MODULE_ALIAS("platform:" DRIVER_NAME
);