sched/doc: Update documentation for base_slice_ns and CONFIG_HZ relation
[sfrench/cifs-2.6.git] / drivers / bus / ts-nbus.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * NBUS driver for TS-4600 based boards
4  *
5  * Copyright (c) 2016 - Savoir-faire Linux
6  * Author: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
7  *
8  * This driver implements a GPIOs bit-banged bus, called the NBUS by Technologic
9  * Systems. It is used to communicate with the peripherals in the FPGA on the
10  * TS-4600 SoM.
11  */
12
13 #include <linux/bitops.h>
14 #include <linux/gpio/consumer.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/mutex.h>
18 #include <linux/of_platform.h>
19 #include <linux/platform_device.h>
20 #include <linux/pwm.h>
21 #include <linux/ts-nbus.h>
22
23 #define TS_NBUS_DIRECTION_IN  0
24 #define TS_NBUS_DIRECTION_OUT 1
25 #define TS_NBUS_WRITE_ADR 0
26 #define TS_NBUS_WRITE_VAL 1
27
28 struct ts_nbus {
29         struct pwm_device *pwm;
30         struct gpio_descs *data;
31         struct gpio_desc *csn;
32         struct gpio_desc *txrx;
33         struct gpio_desc *strobe;
34         struct gpio_desc *ale;
35         struct gpio_desc *rdy;
36         struct mutex lock;
37 };
38
39 /*
40  * request all gpios required by the bus.
41  */
42 static int ts_nbus_init_pdata(struct platform_device *pdev, struct ts_nbus
43                 *ts_nbus)
44 {
45         ts_nbus->data = devm_gpiod_get_array(&pdev->dev, "ts,data",
46                         GPIOD_OUT_HIGH);
47         if (IS_ERR(ts_nbus->data)) {
48                 dev_err(&pdev->dev, "failed to retrieve ts,data-gpio from dts\n");
49                 return PTR_ERR(ts_nbus->data);
50         }
51
52         ts_nbus->csn = devm_gpiod_get(&pdev->dev, "ts,csn", GPIOD_OUT_HIGH);
53         if (IS_ERR(ts_nbus->csn)) {
54                 dev_err(&pdev->dev, "failed to retrieve ts,csn-gpio from dts\n");
55                 return PTR_ERR(ts_nbus->csn);
56         }
57
58         ts_nbus->txrx = devm_gpiod_get(&pdev->dev, "ts,txrx", GPIOD_OUT_HIGH);
59         if (IS_ERR(ts_nbus->txrx)) {
60                 dev_err(&pdev->dev, "failed to retrieve ts,txrx-gpio from dts\n");
61                 return PTR_ERR(ts_nbus->txrx);
62         }
63
64         ts_nbus->strobe = devm_gpiod_get(&pdev->dev, "ts,strobe", GPIOD_OUT_HIGH);
65         if (IS_ERR(ts_nbus->strobe)) {
66                 dev_err(&pdev->dev, "failed to retrieve ts,strobe-gpio from dts\n");
67                 return PTR_ERR(ts_nbus->strobe);
68         }
69
70         ts_nbus->ale = devm_gpiod_get(&pdev->dev, "ts,ale", GPIOD_OUT_HIGH);
71         if (IS_ERR(ts_nbus->ale)) {
72                 dev_err(&pdev->dev, "failed to retrieve ts,ale-gpio from dts\n");
73                 return PTR_ERR(ts_nbus->ale);
74         }
75
76         ts_nbus->rdy = devm_gpiod_get(&pdev->dev, "ts,rdy", GPIOD_IN);
77         if (IS_ERR(ts_nbus->rdy)) {
78                 dev_err(&pdev->dev, "failed to retrieve ts,rdy-gpio from dts\n");
79                 return PTR_ERR(ts_nbus->rdy);
80         }
81
82         return 0;
83 }
84
85 /*
86  * the data gpios are used for reading and writing values, their directions
87  * should be adjusted accordingly.
88  */
89 static void ts_nbus_set_direction(struct ts_nbus *ts_nbus, int direction)
90 {
91         int i;
92
93         for (i = 0; i < 8; i++) {
94                 if (direction == TS_NBUS_DIRECTION_IN)
95                         gpiod_direction_input(ts_nbus->data->desc[i]);
96                 else
97                         /* when used as output the default state of the data
98                          * lines are set to high */
99                         gpiod_direction_output(ts_nbus->data->desc[i], 1);
100         }
101 }
102
103 /*
104  * reset the bus in its initial state.
105  * The data, csn, strobe and ale lines must be zero'ed to let the FPGA knows a
106  * new transaction can be process.
107  */
108 static void ts_nbus_reset_bus(struct ts_nbus *ts_nbus)
109 {
110         DECLARE_BITMAP(values, 8);
111
112         values[0] = 0;
113
114         gpiod_set_array_value_cansleep(8, ts_nbus->data->desc,
115                                        ts_nbus->data->info, values);
116         gpiod_set_value_cansleep(ts_nbus->csn, 0);
117         gpiod_set_value_cansleep(ts_nbus->strobe, 0);
118         gpiod_set_value_cansleep(ts_nbus->ale, 0);
119 }
120
121 /*
122  * let the FPGA knows it can process.
123  */
124 static void ts_nbus_start_transaction(struct ts_nbus *ts_nbus)
125 {
126         gpiod_set_value_cansleep(ts_nbus->strobe, 1);
127 }
128
129 /*
130  * read a byte value from the data gpios.
131  * return 0 on success or negative errno on failure.
132  */
133 static int ts_nbus_read_byte(struct ts_nbus *ts_nbus, u8 *val)
134 {
135         struct gpio_descs *gpios = ts_nbus->data;
136         int ret, i;
137
138         *val = 0;
139         for (i = 0; i < 8; i++) {
140                 ret = gpiod_get_value_cansleep(gpios->desc[i]);
141                 if (ret < 0)
142                         return ret;
143                 if (ret)
144                         *val |= BIT(i);
145         }
146
147         return 0;
148 }
149
150 /*
151  * set the data gpios accordingly to the byte value.
152  */
153 static void ts_nbus_write_byte(struct ts_nbus *ts_nbus, u8 byte)
154 {
155         struct gpio_descs *gpios = ts_nbus->data;
156         DECLARE_BITMAP(values, 8);
157
158         values[0] = byte;
159
160         gpiod_set_array_value_cansleep(8, gpios->desc, gpios->info, values);
161 }
162
163 /*
164  * reading the bus consists of resetting the bus, then notifying the FPGA to
165  * send the data in the data gpios and return the read value.
166  * return 0 on success or negative errno on failure.
167  */
168 static int ts_nbus_read_bus(struct ts_nbus *ts_nbus, u8 *val)
169 {
170         ts_nbus_reset_bus(ts_nbus);
171         ts_nbus_start_transaction(ts_nbus);
172
173         return ts_nbus_read_byte(ts_nbus, val);
174 }
175
176 /*
177  * writing to the bus consists of resetting the bus, then define the type of
178  * command (address/value), write the data and notify the FPGA to retrieve the
179  * value in the data gpios.
180  */
181 static void ts_nbus_write_bus(struct ts_nbus *ts_nbus, int cmd, u8 val)
182 {
183         ts_nbus_reset_bus(ts_nbus);
184
185         if (cmd == TS_NBUS_WRITE_ADR)
186                 gpiod_set_value_cansleep(ts_nbus->ale, 1);
187
188         ts_nbus_write_byte(ts_nbus, val);
189         ts_nbus_start_transaction(ts_nbus);
190 }
191
192 /*
193  * read the value in the FPGA register at the given address.
194  * return 0 on success or negative errno on failure.
195  */
196 int ts_nbus_read(struct ts_nbus *ts_nbus, u8 adr, u16 *val)
197 {
198         int ret, i;
199         u8 byte;
200
201         /* bus access must be atomic */
202         mutex_lock(&ts_nbus->lock);
203
204         /* set the bus in read mode */
205         gpiod_set_value_cansleep(ts_nbus->txrx, 0);
206
207         /* write address */
208         ts_nbus_write_bus(ts_nbus, TS_NBUS_WRITE_ADR, adr);
209
210         /* set the data gpios direction as input before reading */
211         ts_nbus_set_direction(ts_nbus, TS_NBUS_DIRECTION_IN);
212
213         /* reading value MSB first */
214         do {
215                 *val = 0;
216                 byte = 0;
217                 for (i = 1; i >= 0; i--) {
218                         /* read a byte from the bus, leave on error */
219                         ret = ts_nbus_read_bus(ts_nbus, &byte);
220                         if (ret < 0)
221                                 goto err;
222
223                         /* append the byte read to the final value */
224                         *val |= byte << (i * 8);
225                 }
226                 gpiod_set_value_cansleep(ts_nbus->csn, 1);
227                 ret = gpiod_get_value_cansleep(ts_nbus->rdy);
228         } while (ret);
229
230 err:
231         /* restore the data gpios direction as output after reading */
232         ts_nbus_set_direction(ts_nbus, TS_NBUS_DIRECTION_OUT);
233
234         mutex_unlock(&ts_nbus->lock);
235
236         return ret;
237 }
238 EXPORT_SYMBOL_GPL(ts_nbus_read);
239
240 /*
241  * write the desired value in the FPGA register at the given address.
242  */
243 int ts_nbus_write(struct ts_nbus *ts_nbus, u8 adr, u16 val)
244 {
245         int i;
246
247         /* bus access must be atomic */
248         mutex_lock(&ts_nbus->lock);
249
250         /* set the bus in write mode */
251         gpiod_set_value_cansleep(ts_nbus->txrx, 1);
252
253         /* write address */
254         ts_nbus_write_bus(ts_nbus, TS_NBUS_WRITE_ADR, adr);
255
256         /* writing value MSB first */
257         for (i = 1; i >= 0; i--)
258                 ts_nbus_write_bus(ts_nbus, TS_NBUS_WRITE_VAL, (u8)(val >> (i * 8)));
259
260         /* wait for completion */
261         gpiod_set_value_cansleep(ts_nbus->csn, 1);
262         while (gpiod_get_value_cansleep(ts_nbus->rdy) != 0) {
263                 gpiod_set_value_cansleep(ts_nbus->csn, 0);
264                 gpiod_set_value_cansleep(ts_nbus->csn, 1);
265         }
266
267         mutex_unlock(&ts_nbus->lock);
268
269         return 0;
270 }
271 EXPORT_SYMBOL_GPL(ts_nbus_write);
272
273 static int ts_nbus_probe(struct platform_device *pdev)
274 {
275         struct pwm_device *pwm;
276         struct pwm_args pargs;
277         struct device *dev = &pdev->dev;
278         struct ts_nbus *ts_nbus;
279         int ret;
280
281         ts_nbus = devm_kzalloc(dev, sizeof(*ts_nbus), GFP_KERNEL);
282         if (!ts_nbus)
283                 return -ENOMEM;
284
285         mutex_init(&ts_nbus->lock);
286
287         ret = ts_nbus_init_pdata(pdev, ts_nbus);
288         if (ret < 0)
289                 return ret;
290
291         pwm = devm_pwm_get(dev, NULL);
292         if (IS_ERR(pwm)) {
293                 ret = PTR_ERR(pwm);
294                 if (ret != -EPROBE_DEFER)
295                         dev_err(dev, "unable to request PWM\n");
296                 return ret;
297         }
298
299         pwm_get_args(pwm, &pargs);
300         if (!pargs.period) {
301                 dev_err(&pdev->dev, "invalid PWM period\n");
302                 return -EINVAL;
303         }
304
305         /*
306          * FIXME: pwm_apply_args() should be removed when switching to
307          * the atomic PWM API.
308          */
309         pwm_apply_args(pwm);
310         ret = pwm_config(pwm, pargs.period, pargs.period);
311         if (ret < 0)
312                 return ret;
313
314         /*
315          * we can now start the FPGA and populate the peripherals.
316          */
317         pwm_enable(pwm);
318         ts_nbus->pwm = pwm;
319
320         /*
321          * let the child nodes retrieve this instance of the ts-nbus.
322          */
323         dev_set_drvdata(dev, ts_nbus);
324
325         ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
326         if (ret < 0)
327                 return ret;
328
329         dev_info(dev, "initialized\n");
330
331         return 0;
332 }
333
334 static void ts_nbus_remove(struct platform_device *pdev)
335 {
336         struct ts_nbus *ts_nbus = dev_get_drvdata(&pdev->dev);
337
338         /* shutdown the FPGA */
339         mutex_lock(&ts_nbus->lock);
340         pwm_disable(ts_nbus->pwm);
341         mutex_unlock(&ts_nbus->lock);
342 }
343
344 static const struct of_device_id ts_nbus_of_match[] = {
345         { .compatible = "technologic,ts-nbus", },
346         { },
347 };
348 MODULE_DEVICE_TABLE(of, ts_nbus_of_match);
349
350 static struct platform_driver ts_nbus_driver = {
351         .probe          = ts_nbus_probe,
352         .remove_new     = ts_nbus_remove,
353         .driver         = {
354                 .name   = "ts_nbus",
355                 .of_match_table = ts_nbus_of_match,
356         },
357 };
358
359 module_platform_driver(ts_nbus_driver);
360
361 MODULE_ALIAS("platform:ts_nbus");
362 MODULE_AUTHOR("Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>");
363 MODULE_DESCRIPTION("Technologic Systems NBUS");
364 MODULE_LICENSE("GPL v2");