xref: /openbmc/linux/drivers/siox/siox-bus-gpio.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1fd639726SUwe Kleine-König // SPDX-License-Identifier: GPL-2.0
2fd639726SUwe Kleine-König /*
3fd639726SUwe Kleine-König  * Copyright (C) 2015-2017 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
4fd639726SUwe Kleine-König  */
5fd639726SUwe Kleine-König 
6fd639726SUwe Kleine-König #include <linux/gpio/consumer.h>
7fd639726SUwe Kleine-König #include <linux/module.h>
8ac316725SRandy Dunlap #include <linux/mod_devicetable.h>
9fd639726SUwe Kleine-König #include <linux/platform_device.h>
10fd639726SUwe Kleine-König 
11fd639726SUwe Kleine-König #include <linux/delay.h>
12fd639726SUwe Kleine-König 
13fd639726SUwe Kleine-König #include "siox.h"
14fd639726SUwe Kleine-König 
15fd639726SUwe Kleine-König #define DRIVER_NAME "siox-gpio"
16fd639726SUwe Kleine-König 
17fd639726SUwe Kleine-König struct siox_gpio_ddata {
18fd639726SUwe Kleine-König 	struct gpio_desc *din;
19fd639726SUwe Kleine-König 	struct gpio_desc *dout;
20fd639726SUwe Kleine-König 	struct gpio_desc *dclk;
21fd639726SUwe Kleine-König 	struct gpio_desc *dld;
22fd639726SUwe Kleine-König };
23fd639726SUwe Kleine-König 
24fd639726SUwe Kleine-König static unsigned int siox_clkhigh_ns = 1000;
25fd639726SUwe Kleine-König static unsigned int siox_loadhigh_ns;
26fd639726SUwe Kleine-König static unsigned int siox_bytegap_ns;
27fd639726SUwe Kleine-König 
siox_gpio_pushpull(struct siox_master * smaster,size_t setbuf_len,const u8 setbuf[],size_t getbuf_len,u8 getbuf[])28fd639726SUwe Kleine-König static int siox_gpio_pushpull(struct siox_master *smaster,
29fd639726SUwe Kleine-König 			      size_t setbuf_len, const u8 setbuf[],
30fd639726SUwe Kleine-König 			      size_t getbuf_len, u8 getbuf[])
31fd639726SUwe Kleine-König {
32fd639726SUwe Kleine-König 	struct siox_gpio_ddata *ddata = siox_master_get_devdata(smaster);
33fd639726SUwe Kleine-König 	size_t i;
34fd639726SUwe Kleine-König 	size_t cycles = max(setbuf_len, getbuf_len);
35fd639726SUwe Kleine-König 
36fd639726SUwe Kleine-König 	/* reset data and clock */
37fd639726SUwe Kleine-König 	gpiod_set_value_cansleep(ddata->dout, 0);
38fd639726SUwe Kleine-König 	gpiod_set_value_cansleep(ddata->dclk, 0);
39fd639726SUwe Kleine-König 
40fd639726SUwe Kleine-König 	gpiod_set_value_cansleep(ddata->dld, 1);
41fd639726SUwe Kleine-König 	ndelay(siox_loadhigh_ns);
42fd639726SUwe Kleine-König 	gpiod_set_value_cansleep(ddata->dld, 0);
43fd639726SUwe Kleine-König 
44fd639726SUwe Kleine-König 	for (i = 0; i < cycles; ++i) {
45fd639726SUwe Kleine-König 		u8 set = 0, get = 0;
46fd639726SUwe Kleine-König 		size_t j;
47fd639726SUwe Kleine-König 
48fd639726SUwe Kleine-König 		if (i >= cycles - setbuf_len)
49fd639726SUwe Kleine-König 			set = setbuf[i - (cycles - setbuf_len)];
50fd639726SUwe Kleine-König 
51fd639726SUwe Kleine-König 		for (j = 0; j < 8; ++j) {
52fd639726SUwe Kleine-König 			get <<= 1;
53fd639726SUwe Kleine-König 			if (gpiod_get_value_cansleep(ddata->din))
54fd639726SUwe Kleine-König 				get |= 1;
55fd639726SUwe Kleine-König 
56fd639726SUwe Kleine-König 			/* DOUT is logically inverted */
57fd639726SUwe Kleine-König 			gpiod_set_value_cansleep(ddata->dout, !(set & 0x80));
58fd639726SUwe Kleine-König 			set <<= 1;
59fd639726SUwe Kleine-König 
60fd639726SUwe Kleine-König 			gpiod_set_value_cansleep(ddata->dclk, 1);
61fd639726SUwe Kleine-König 			ndelay(siox_clkhigh_ns);
62fd639726SUwe Kleine-König 			gpiod_set_value_cansleep(ddata->dclk, 0);
63fd639726SUwe Kleine-König 		}
64fd639726SUwe Kleine-König 
65fd639726SUwe Kleine-König 		if (i < getbuf_len)
66fd639726SUwe Kleine-König 			getbuf[i] = get;
67fd639726SUwe Kleine-König 
68fd639726SUwe Kleine-König 		ndelay(siox_bytegap_ns);
69fd639726SUwe Kleine-König 	}
70fd639726SUwe Kleine-König 
71fd639726SUwe Kleine-König 	gpiod_set_value_cansleep(ddata->dld, 1);
72fd639726SUwe Kleine-König 	ndelay(siox_loadhigh_ns);
73fd639726SUwe Kleine-König 	gpiod_set_value_cansleep(ddata->dld, 0);
74fd639726SUwe Kleine-König 
75fd639726SUwe Kleine-König 	/*
76fd639726SUwe Kleine-König 	 * Resetting dout isn't necessary protocol wise, but it makes the
77fd639726SUwe Kleine-König 	 * signals more pretty because the dout level is deterministic between
78fd639726SUwe Kleine-König 	 * cycles. Note that this only affects dout between the master and the
79fd639726SUwe Kleine-König 	 * first siox device. dout for the later devices depend on the output of
80fd639726SUwe Kleine-König 	 * the previous siox device.
81fd639726SUwe Kleine-König 	 */
82fd639726SUwe Kleine-König 	gpiod_set_value_cansleep(ddata->dout, 0);
83fd639726SUwe Kleine-König 
84fd639726SUwe Kleine-König 	return 0;
85fd639726SUwe Kleine-König }
86fd639726SUwe Kleine-König 
siox_gpio_probe(struct platform_device * pdev)87fd639726SUwe Kleine-König static int siox_gpio_probe(struct platform_device *pdev)
88fd639726SUwe Kleine-König {
89fd639726SUwe Kleine-König 	struct device *dev = &pdev->dev;
90fd639726SUwe Kleine-König 	struct siox_gpio_ddata *ddata;
91fd639726SUwe Kleine-König 	int ret;
92fd639726SUwe Kleine-König 	struct siox_master *smaster;
93fd639726SUwe Kleine-König 
94fd639726SUwe Kleine-König 	smaster = siox_master_alloc(&pdev->dev, sizeof(*ddata));
95fd639726SUwe Kleine-König 	if (!smaster) {
96fd639726SUwe Kleine-König 		dev_err(dev, "failed to allocate siox master\n");
97fd639726SUwe Kleine-König 		return -ENOMEM;
98fd639726SUwe Kleine-König 	}
99fd639726SUwe Kleine-König 
100fd639726SUwe Kleine-König 	platform_set_drvdata(pdev, smaster);
101fd639726SUwe Kleine-König 	ddata = siox_master_get_devdata(smaster);
102fd639726SUwe Kleine-König 
103fd639726SUwe Kleine-König 	ddata->din = devm_gpiod_get(dev, "din", GPIOD_IN);
104fd639726SUwe Kleine-König 	if (IS_ERR(ddata->din)) {
105*75020f2dSThorsten Scherer 		ret = dev_err_probe(dev, PTR_ERR(ddata->din),
106*75020f2dSThorsten Scherer 				    "Failed to get din GPIO\n");
107fd639726SUwe Kleine-König 		goto err;
108fd639726SUwe Kleine-König 	}
109fd639726SUwe Kleine-König 
110fd639726SUwe Kleine-König 	ddata->dout = devm_gpiod_get(dev, "dout", GPIOD_OUT_LOW);
111fd639726SUwe Kleine-König 	if (IS_ERR(ddata->dout)) {
112*75020f2dSThorsten Scherer 		ret = dev_err_probe(dev, PTR_ERR(ddata->dout),
113*75020f2dSThorsten Scherer 				    "Failed to get dout GPIO\n");
114fd639726SUwe Kleine-König 		goto err;
115fd639726SUwe Kleine-König 	}
116fd639726SUwe Kleine-König 
117fd639726SUwe Kleine-König 	ddata->dclk = devm_gpiod_get(dev, "dclk", GPIOD_OUT_LOW);
118fd639726SUwe Kleine-König 	if (IS_ERR(ddata->dclk)) {
119*75020f2dSThorsten Scherer 		ret = dev_err_probe(dev, PTR_ERR(ddata->dclk),
120*75020f2dSThorsten Scherer 				    "Failed to get dclk GPIO\n");
121fd639726SUwe Kleine-König 		goto err;
122fd639726SUwe Kleine-König 	}
123fd639726SUwe Kleine-König 
124fd639726SUwe Kleine-König 	ddata->dld = devm_gpiod_get(dev, "dld", GPIOD_OUT_LOW);
125fd639726SUwe Kleine-König 	if (IS_ERR(ddata->dld)) {
126*75020f2dSThorsten Scherer 		ret = dev_err_probe(dev, PTR_ERR(ddata->dld),
127*75020f2dSThorsten Scherer 				    "Failed to get dld GPIO\n");
128fd639726SUwe Kleine-König 		goto err;
129fd639726SUwe Kleine-König 	}
130fd639726SUwe Kleine-König 
131fd639726SUwe Kleine-König 	smaster->pushpull = siox_gpio_pushpull;
132fd639726SUwe Kleine-König 	/* XXX: determine automatically like spi does */
133fd639726SUwe Kleine-König 	smaster->busno = 0;
134fd639726SUwe Kleine-König 
135fd639726SUwe Kleine-König 	ret = siox_master_register(smaster);
136fd639726SUwe Kleine-König 	if (ret) {
137*75020f2dSThorsten Scherer 		dev_err_probe(dev, ret,
138*75020f2dSThorsten Scherer 			      "Failed to register siox master\n");
139fd639726SUwe Kleine-König err:
140fd639726SUwe Kleine-König 		siox_master_put(smaster);
141fd639726SUwe Kleine-König 	}
142fd639726SUwe Kleine-König 
143fd639726SUwe Kleine-König 	return ret;
144fd639726SUwe Kleine-König }
145fd639726SUwe Kleine-König 
siox_gpio_remove(struct platform_device * pdev)146fd639726SUwe Kleine-König static int siox_gpio_remove(struct platform_device *pdev)
147fd639726SUwe Kleine-König {
148fd639726SUwe Kleine-König 	struct siox_master *master = platform_get_drvdata(pdev);
149fd639726SUwe Kleine-König 
150fd639726SUwe Kleine-König 	siox_master_unregister(master);
151fd639726SUwe Kleine-König 
152fd639726SUwe Kleine-König 	return 0;
153fd639726SUwe Kleine-König }
154fd639726SUwe Kleine-König 
155fd639726SUwe Kleine-König static const struct of_device_id siox_gpio_dt_ids[] = {
156fd639726SUwe Kleine-König 	{ .compatible = "eckelmann,siox-gpio", },
157fd639726SUwe Kleine-König 	{ /* sentinel */ }
158fd639726SUwe Kleine-König };
159fd639726SUwe Kleine-König MODULE_DEVICE_TABLE(of, siox_gpio_dt_ids);
160fd639726SUwe Kleine-König 
161fd639726SUwe Kleine-König static struct platform_driver siox_gpio_driver = {
162fd639726SUwe Kleine-König 	.probe = siox_gpio_probe,
163fd639726SUwe Kleine-König 	.remove = siox_gpio_remove,
164fd639726SUwe Kleine-König 
165fd639726SUwe Kleine-König 	.driver = {
166fd639726SUwe Kleine-König 		.name = DRIVER_NAME,
167fd639726SUwe Kleine-König 		.of_match_table = siox_gpio_dt_ids,
168fd639726SUwe Kleine-König 	},
169fd639726SUwe Kleine-König };
170fd639726SUwe Kleine-König module_platform_driver(siox_gpio_driver);
171fd639726SUwe Kleine-König 
172fd639726SUwe Kleine-König MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
173fd639726SUwe Kleine-König MODULE_LICENSE("GPL v2");
174fd639726SUwe Kleine-König MODULE_ALIAS("platform:" DRIVER_NAME);
175