summaryrefslogtreecommitdiffstats
path: root/drivers/siox
diff options
context:
space:
mode:
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>2017-12-18 11:59:07 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-12-19 03:26:00 -0500
commitbbecb07fa0af9a41507ce06d4631fdb3b5059417 (patch)
tree5326e5865a1100ab9dda4f774d01a5a8de7996de /drivers/siox
parent0ba002bc4393dcfae031fc707b11c094b46a5048 (diff)
siox: new driver framework for eckelmann SIOX
SIOX is a bus system invented at Eckelmann AG to control their building management and refrigeration systems. Traditionally the bus was implemented on custom microcontrollers, today Linux based machines are in use, too. The topology on a SIOX bus looks as follows: ,------->--DCLK-->---------------+----------------------. ^ v v ,--------. ,----------------------. ,------ | | | ,--------------. | | | |--->--DOUT-->---|->-|shift register|->-|--->---| | | | `--------------' | | | master | | device | | device | | | ,--------------. | | | |---<--DIN---<---|-<-|shift register|-<-|---<---| | | | `--------------' | | `--------' `----------------------' `------ v ^ ^ `----------DLD-------------------+----------------------' There are two control lines (DCLK and DLD) driven from the bus master to all devices in parallel and two daisy chained data lines, one for input and one for output. DCLK is the clock to shift both chains by a single bit. On an edge of DLD the devices latch both their input and output shift registers. This patch adds a framework for this bus type. Acked-by: Gavin Schenk <g.schenk@eckelmann.de> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/siox')
-rw-r--r--drivers/siox/Kconfig9
-rw-r--r--drivers/siox/Makefile1
-rw-r--r--drivers/siox/siox-core.c922
-rw-r--r--drivers/siox/siox.h49
4 files changed, 981 insertions, 0 deletions
diff --git a/drivers/siox/Kconfig b/drivers/siox/Kconfig
new file mode 100644
index 000000000000..bd24d9b50dc6
--- /dev/null
+++ b/drivers/siox/Kconfig
@@ -0,0 +1,9 @@
1menuconfig SIOX
2 tristate "Eckelmann SIOX Support"
3 help
4 SIOX stands for Serial Input Output eXtension and is a synchronous
5 bus system invented by Eckelmann AG. It is used in their control and
6 remote monitoring systems for commercial and industrial refrigeration
7 to drive additional I/O units.
8
9 Unless you know better, it is probably safe to say "no" here.
diff --git a/drivers/siox/Makefile b/drivers/siox/Makefile
new file mode 100644
index 000000000000..d55cb5e08868
--- /dev/null
+++ b/drivers/siox/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_SIOX) += siox-core.o
diff --git a/drivers/siox/siox-core.c b/drivers/siox/siox-core.c
new file mode 100644
index 000000000000..16585c1b2b9e
--- /dev/null
+++ b/drivers/siox/siox-core.c
@@ -0,0 +1,922 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2015-2017 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
4 */
5#include <linux/kernel.h>
6#include <linux/device.h>
7#include <linux/module.h>
8#include <linux/slab.h>
9#include <linux/sysfs.h>
10
11#include "siox.h"
12
13/*
14 * The lowest bit in the SIOX status word signals if the in-device watchdog is
15 * ok. If the bit is set, the device is functional.
16 *
17 * On writing the watchdog timer is reset when this bit toggles.
18 */
19#define SIOX_STATUS_WDG 0x01
20
21/*
22 * Bits 1 to 3 of the status word read as the bitwise negation of what was
23 * clocked in before. The value clocked in is changed in each cycle and so
24 * allows to detect transmit/receive problems.
25 */
26#define SIOX_STATUS_COUNTER 0x0e
27
28/*
29 * Each Siox-Device has a 4 bit type number that is neither 0 nor 15. This is
30 * available in the upper nibble of the read status.
31 *
32 * On write these bits are DC.
33 */
34#define SIOX_STATUS_TYPE 0xf0
35
36static bool siox_is_registered;
37
38static void siox_master_lock(struct siox_master *smaster)
39{
40 mutex_lock(&smaster->lock);
41}
42
43static void siox_master_unlock(struct siox_master *smaster)
44{
45 mutex_unlock(&smaster->lock);
46}
47
48static inline u8 siox_status_clean(u8 status_read, u8 status_written)
49{
50 /*
51 * bits 3:1 of status sample the respective bit in the status
52 * byte written in the previous cycle but inverted. So if you wrote the
53 * status word as 0xa before (counter = 0b101), it is expected to get
54 * back the counter bits as 0b010.
55 *
56 * So given the last status written this function toggles the there
57 * unset counter bits in the read value such that the counter bits in
58 * the return value are all zero iff the bits were read as expected to
59 * simplify error detection.
60 */
61
62 return status_read ^ (~status_written & 0xe);
63}
64
65static bool siox_device_counter_error(struct siox_device *sdevice,
66 u8 status_clean)
67{
68 return (status_clean & SIOX_STATUS_COUNTER) != 0;
69}
70
71static bool siox_device_type_error(struct siox_device *sdevice, u8 status_clean)
72{
73 u8 statustype = (status_clean & SIOX_STATUS_TYPE) >> 4;
74
75 /*
76 * If the device knows which value the type bits should have, check
77 * against this value otherwise just rule out the invalid values 0b0000
78 * and 0b1111.
79 */
80 if (sdevice->statustype) {
81 if (statustype != sdevice->statustype)
82 return true;
83 } else {
84 switch (statustype) {
85 case 0:
86 case 0xf:
87 return true;
88 }
89 }
90
91 return false;
92}
93
94static bool siox_device_wdg_error(struct siox_device *sdevice, u8 status_clean)
95{
96 return (status_clean & SIOX_STATUS_WDG) == 0;
97}
98
99/*
100 * If there is a type or counter error the device is called "unsynced".
101 */
102bool siox_device_synced(struct siox_device *sdevice)
103{
104 if (siox_device_type_error(sdevice, sdevice->status_read_clean))
105 return false;
106
107 return !siox_device_counter_error(sdevice, sdevice->status_read_clean);
108
109}
110EXPORT_SYMBOL_GPL(siox_device_synced);
111
112/*
113 * A device is called "connected" if it is synced and the watchdog is not
114 * asserted.
115 */
116bool siox_device_connected(struct siox_device *sdevice)
117{
118 if (!siox_device_synced(sdevice))
119 return false;
120
121 return !siox_device_wdg_error(sdevice, sdevice->status_read_clean);
122}
123EXPORT_SYMBOL_GPL(siox_device_connected);
124
125static void siox_poll(struct siox_master *smaster)
126{
127 struct siox_device *sdevice;
128 size_t i = smaster->setbuf_len;
129 int unsync_error = 0;
130
131 smaster->last_poll = jiffies;
132
133 /*
134 * The counter bits change in each second cycle, the watchdog bit
135 * toggles each time.
136 * The counter bits hold values from [0, 6]. 7 would be possible
137 * theoretically but the protocol designer considered that a bad idea
138 * for reasons unknown today. (Maybe that's because then the status read
139 * back has only zeros in the counter bits then which might be confused
140 * with a stuck-at-0 error. But for the same reason (with s/0/1/) 0
141 * could be skipped.)
142 */
143 if (++smaster->status > 0x0d)
144 smaster->status = 0;
145
146 memset(smaster->buf, 0, smaster->setbuf_len);
147
148 /* prepare data pushed out to devices in buf[0..setbuf_len) */
149 list_for_each_entry(sdevice, &smaster->devices, node) {
150 struct siox_driver *sdriver =
151 to_siox_driver(sdevice->dev.driver);
152 sdevice->status_written = smaster->status;
153
154 i -= sdevice->inbytes;
155
156 /*
157 * If the device or a previous one is unsynced, don't pet the
158 * watchdog. This is done to ensure that the device is kept in
159 * reset when something is wrong.
160 */
161 if (!siox_device_synced(sdevice))
162 unsync_error = 1;
163
164 if (sdriver && !unsync_error)
165 sdriver->set_data(sdevice, sdevice->status_written,
166 &smaster->buf[i + 1]);
167 else
168 /*
169 * Don't trigger watchdog if there is no driver or a
170 * sync problem
171 */
172 sdevice->status_written &= ~SIOX_STATUS_WDG;
173
174 smaster->buf[i] = sdevice->status_written;
175 }
176
177 smaster->pushpull(smaster, smaster->setbuf_len, smaster->buf,
178 smaster->getbuf_len,
179 smaster->buf + smaster->setbuf_len);
180
181 unsync_error = 0;
182
183 /* interpret data pulled in from devices in buf[setbuf_len..] */
184 i = smaster->setbuf_len;
185 list_for_each_entry(sdevice, &smaster->devices, node) {
186 struct siox_driver *sdriver =
187 to_siox_driver(sdevice->dev.driver);
188 u8 status = smaster->buf[i + sdevice->outbytes - 1];
189 u8 status_clean;
190 u8 prev_status_clean = sdevice->status_read_clean;
191 bool synced = true;
192 bool connected = true;
193
194 if (!siox_device_synced(sdevice))
195 unsync_error = 1;
196
197 /*
198 * If the watchdog bit wasn't toggled in this cycle, report the
199 * watchdog as active to give a consistent view for drivers and
200 * sysfs consumers.
201 */
202 if (!sdriver || unsync_error)
203 status &= ~SIOX_STATUS_WDG;
204
205 status_clean =
206 siox_status_clean(status,
207 sdevice->status_written_lastcycle);
208
209 /* Check counter bits */
210 if (siox_device_counter_error(sdevice, status_clean)) {
211 bool prev_counter_error;
212
213 synced = false;
214
215 /* only report a new error if the last cycle was ok */
216 prev_counter_error =
217 siox_device_counter_error(sdevice,
218 prev_status_clean);
219 if (!prev_counter_error) {
220 sdevice->status_errors++;
221 sysfs_notify_dirent(sdevice->status_errors_kn);
222 }
223 }
224
225 /* Check type bits */
226 if (siox_device_type_error(sdevice, status_clean))
227 synced = false;
228
229 /* If the device is unsynced report the watchdog as active */
230 if (!synced) {
231 status &= ~SIOX_STATUS_WDG;
232 status_clean &= ~SIOX_STATUS_WDG;
233 }
234
235 if (siox_device_wdg_error(sdevice, status_clean))
236 connected = false;
237
238 /* The watchdog state changed just now */
239 if ((status_clean ^ prev_status_clean) & SIOX_STATUS_WDG) {
240 sysfs_notify_dirent(sdevice->watchdog_kn);
241
242 if (siox_device_wdg_error(sdevice, status_clean)) {
243 struct kernfs_node *wd_errs =
244 sdevice->watchdog_errors_kn;
245
246 sdevice->watchdog_errors++;
247 sysfs_notify_dirent(wd_errs);
248 }
249 }
250
251 if (connected != sdevice->connected)
252 sysfs_notify_dirent(sdevice->connected_kn);
253
254 sdevice->status_read_clean = status_clean;
255 sdevice->status_written_lastcycle = sdevice->status_written;
256 sdevice->connected = connected;
257
258 /* only give data read to driver if the device is connected */
259 if (sdriver && connected)
260 sdriver->get_data(sdevice, &smaster->buf[i]);
261
262 i += sdevice->outbytes;
263 }
264}
265
266static int siox_poll_thread(void *data)
267{
268 struct siox_master *smaster = data;
269 signed long timeout = 0;
270
271 get_device(&smaster->dev);
272
273 for (;;) {
274 if (kthread_should_stop()) {
275 put_device(&smaster->dev);
276 return 0;
277 }
278
279 siox_master_lock(smaster);
280
281 if (smaster->active) {
282 unsigned long next_poll =
283 smaster->last_poll + smaster->poll_interval;
284 if (time_is_before_eq_jiffies(next_poll))
285 siox_poll(smaster);
286
287 timeout = smaster->poll_interval -
288 (jiffies - smaster->last_poll);
289 } else {
290 timeout = MAX_SCHEDULE_TIMEOUT;
291 }
292
293 /*
294 * Set the task to idle while holding the lock. This makes sure
295 * that we don't sleep too long when the bus is reenabled before
296 * schedule_timeout is reached.
297 */
298 if (timeout > 0)
299 set_current_state(TASK_IDLE);
300
301 siox_master_unlock(smaster);
302
303 if (timeout > 0)
304 schedule_timeout(timeout);
305
306 /*
307 * I'm not clear if/why it is important to set the state to
308 * RUNNING again, but it fixes a "do not call blocking ops when
309 * !TASK_RUNNING;"-warning.
310 */
311 set_current_state(TASK_RUNNING);
312 }
313}
314
315static int __siox_start(struct siox_master *smaster)
316{
317 if (!(smaster->setbuf_len + smaster->getbuf_len))
318 return -ENODEV;
319
320 if (!smaster->buf)
321 return -ENOMEM;
322
323 if (smaster->active)
324 return 0;
325
326 smaster->active = 1;
327 wake_up_process(smaster->poll_thread);
328
329 return 1;
330}
331
332static int siox_start(struct siox_master *smaster)
333{
334 int ret;
335
336 siox_master_lock(smaster);
337 ret = __siox_start(smaster);
338 siox_master_unlock(smaster);
339
340 return ret;
341}
342
343static int __siox_stop(struct siox_master *smaster)
344{
345 if (smaster->active) {
346 struct siox_device *sdevice;
347
348 smaster->active = 0;
349
350 list_for_each_entry(sdevice, &smaster->devices, node) {
351 if (sdevice->connected)
352 sysfs_notify_dirent(sdevice->connected_kn);
353 sdevice->connected = false;
354 }
355
356 return 1;
357 }
358 return 0;
359}
360
361static int siox_stop(struct siox_master *smaster)
362{
363 int ret;
364
365 siox_master_lock(smaster);
366 ret = __siox_stop(smaster);
367 siox_master_unlock(smaster);
368
369 return ret;
370}
371
372static ssize_t type_show(struct device *dev,
373 struct device_attribute *attr, char *buf)
374{
375 struct siox_device *sdev = to_siox_device(dev);
376
377 return sprintf(buf, "%s\n", sdev->type);
378}
379
380static DEVICE_ATTR_RO(type);
381
382static ssize_t inbytes_show(struct device *dev,
383 struct device_attribute *attr, char *buf)
384{
385 struct siox_device *sdev = to_siox_device(dev);
386
387 return sprintf(buf, "%zu\n", sdev->inbytes);
388}
389
390static DEVICE_ATTR_RO(inbytes);
391
392static ssize_t outbytes_show(struct device *dev,
393 struct device_attribute *attr, char *buf)
394{
395 struct siox_device *sdev = to_siox_device(dev);
396
397 return sprintf(buf, "%zu\n", sdev->outbytes);
398}
399
400static DEVICE_ATTR_RO(outbytes);
401
402static ssize_t status_errors_show(struct device *dev,
403 struct device_attribute *attr, char *buf)
404{
405 struct siox_device *sdev = to_siox_device(dev);
406 unsigned int status_errors;
407
408 siox_master_lock(sdev->smaster);
409
410 status_errors = sdev->status_errors;
411
412 siox_master_unlock(sdev->smaster);
413
414 return sprintf(buf, "%u\n", status_errors);
415}
416
417static DEVICE_ATTR_RO(status_errors);
418
419static ssize_t connected_show(struct device *dev,
420 struct device_attribute *attr, char *buf)
421{
422 struct siox_device *sdev = to_siox_device(dev);
423 bool connected;
424
425 siox_master_lock(sdev->smaster);
426
427 connected = sdev->connected;
428
429 siox_master_unlock(sdev->smaster);
430
431 return sprintf(buf, "%u\n", connected);
432}
433
434static DEVICE_ATTR_RO(connected);
435
436static ssize_t watchdog_show(struct device *dev,
437 struct device_attribute *attr, char *buf)
438{
439 struct siox_device *sdev = to_siox_device(dev);
440 u8 status;
441
442 siox_master_lock(sdev->smaster);
443
444 status = sdev->status_read_clean;
445
446 siox_master_unlock(sdev->smaster);
447
448 return sprintf(buf, "%d\n", status & SIOX_STATUS_WDG);
449}
450
451static DEVICE_ATTR_RO(watchdog);
452
453static ssize_t watchdog_errors_show(struct device *dev,
454 struct device_attribute *attr, char *buf)
455{
456 struct siox_device *sdev = to_siox_device(dev);
457 unsigned int watchdog_errors;
458
459 siox_master_lock(sdev->smaster);
460
461 watchdog_errors = sdev->watchdog_errors;
462
463 siox_master_unlock(sdev->smaster);
464
465 return sprintf(buf, "%u\n", watchdog_errors);
466}
467
468static DEVICE_ATTR_RO(watchdog_errors);
469
470static struct attribute *siox_device_attrs[] = {
471 &dev_attr_type.attr,
472 &dev_attr_inbytes.attr,
473 &dev_attr_outbytes.attr,
474 &dev_attr_status_errors.attr,
475 &dev_attr_connected.attr,
476 &dev_attr_watchdog.attr,
477 &dev_attr_watchdog_errors.attr,
478 NULL
479};
480ATTRIBUTE_GROUPS(siox_device);
481
482static void siox_device_release(struct device *dev)
483{
484 struct siox_device *sdevice = to_siox_device(dev);
485
486 kfree(sdevice);
487}
488
489static struct device_type siox_device_type = {
490 .groups = siox_device_groups,
491 .release = siox_device_release,
492};
493
494static int siox_match(struct device *dev, struct device_driver *drv)
495{
496 if (dev->type != &siox_device_type)
497 return 0;
498
499 /* up to now there is only a single driver so keeping this simple */
500 return 1;
501}
502
503static struct bus_type siox_bus_type = {
504 .name = "siox",
505 .match = siox_match,
506};
507
508static int siox_driver_probe(struct device *dev)
509{
510 struct siox_driver *sdriver = to_siox_driver(dev->driver);
511 struct siox_device *sdevice = to_siox_device(dev);
512 int ret;
513
514 ret = sdriver->probe(sdevice);
515 return ret;
516}
517
518static int siox_driver_remove(struct device *dev)
519{
520 struct siox_driver *sdriver =
521 container_of(dev->driver, struct siox_driver, driver);
522 struct siox_device *sdevice = to_siox_device(dev);
523 int ret;
524
525 ret = sdriver->remove(sdevice);
526 return ret;
527}
528
529static void siox_driver_shutdown(struct device *dev)
530{
531 struct siox_driver *sdriver =
532 container_of(dev->driver, struct siox_driver, driver);
533 struct siox_device *sdevice = to_siox_device(dev);
534
535 sdriver->shutdown(sdevice);
536}
537
538static ssize_t active_show(struct device *dev,
539 struct device_attribute *attr, char *buf)
540{
541 struct siox_master *smaster = to_siox_master(dev);
542
543 return sprintf(buf, "%d\n", smaster->active);
544}
545
546static ssize_t active_store(struct device *dev,
547 struct device_attribute *attr,
548 const char *buf, size_t count)
549{
550 struct siox_master *smaster = to_siox_master(dev);
551 int ret;
552 int active;
553
554 ret = kstrtoint(buf, 0, &active);
555 if (ret < 0)
556 return ret;
557
558 if (active)
559 ret = siox_start(smaster);
560 else
561 ret = siox_stop(smaster);
562
563 if (ret < 0)
564 return ret;
565
566 return count;
567}
568
569static DEVICE_ATTR_RW(active);
570
571static struct siox_device *siox_device_add(struct siox_master *smaster,
572 const char *type, size_t inbytes,
573 size_t outbytes, u8 statustype);
574
575static ssize_t device_add_store(struct device *dev,
576 struct device_attribute *attr,
577 const char *buf, size_t count)
578{
579 struct siox_master *smaster = to_siox_master(dev);
580 int ret;
581 char type[20] = "";
582 size_t inbytes = 0, outbytes = 0;
583 u8 statustype = 0;
584
585 ret = sscanf(buf, "%20s %zu %zu %hhu", type, &inbytes,
586 &outbytes, &statustype);
587 if (ret != 3 && ret != 4)
588 return -EINVAL;
589
590 if (strcmp(type, "siox-12x8") || inbytes != 2 || outbytes != 4)
591 return -EINVAL;
592
593 siox_device_add(smaster, "siox-12x8", inbytes, outbytes, statustype);
594
595 return count;
596}
597
598static DEVICE_ATTR_WO(device_add);
599
600static void siox_device_remove(struct siox_master *smaster);
601
602static ssize_t device_remove_store(struct device *dev,
603 struct device_attribute *attr,
604 const char *buf, size_t count)
605{
606 struct siox_master *smaster = to_siox_master(dev);
607
608 /* XXX? require to write <type> <inbytes> <outbytes> */
609 siox_device_remove(smaster);
610
611 return count;
612}
613
614static DEVICE_ATTR_WO(device_remove);
615
616static ssize_t poll_interval_ns_show(struct device *dev,
617 struct device_attribute *attr, char *buf)
618{
619 struct siox_master *smaster = to_siox_master(dev);
620
621 return sprintf(buf, "%lld\n", jiffies_to_nsecs(smaster->poll_interval));
622}
623
624static ssize_t poll_interval_ns_store(struct device *dev,
625 struct device_attribute *attr,
626 const char *buf, size_t count)
627{
628 struct siox_master *smaster = to_siox_master(dev);
629 int ret;
630 u64 val;
631
632 ret = kstrtou64(buf, 0, &val);
633 if (ret < 0)
634 return ret;
635
636 siox_master_lock(smaster);
637
638 smaster->poll_interval = nsecs_to_jiffies(val);
639
640 siox_master_unlock(smaster);
641
642 return count;
643}
644
645static DEVICE_ATTR_RW(poll_interval_ns);
646
647static struct attribute *siox_master_attrs[] = {
648 &dev_attr_active.attr,
649 &dev_attr_device_add.attr,
650 &dev_attr_device_remove.attr,
651 &dev_attr_poll_interval_ns.attr,
652 NULL
653};
654ATTRIBUTE_GROUPS(siox_master);
655
656static void siox_master_release(struct device *dev)
657{
658 struct siox_master *smaster = to_siox_master(dev);
659
660 kfree(smaster);
661}
662
663static struct device_type siox_master_type = {
664 .groups = siox_master_groups,
665 .release = siox_master_release,
666};
667
668struct siox_master *siox_master_alloc(struct device *dev,
669 size_t size)
670{
671 struct siox_master *smaster;
672
673 if (!dev)
674 return NULL;
675
676 smaster = kzalloc(sizeof(*smaster) + size, GFP_KERNEL);
677 if (!smaster)
678 return NULL;
679
680 device_initialize(&smaster->dev);
681
682 smaster->busno = -1;
683 smaster->dev.bus = &siox_bus_type;
684 smaster->dev.type = &siox_master_type;
685 smaster->dev.parent = dev;
686 smaster->poll_interval = DIV_ROUND_UP(HZ, 40);
687
688 dev_set_drvdata(&smaster->dev, &smaster[1]);
689
690 return smaster;
691}
692EXPORT_SYMBOL_GPL(siox_master_alloc);
693
694int siox_master_register(struct siox_master *smaster)
695{
696 int ret;
697
698 if (!siox_is_registered)
699 return -EPROBE_DEFER;
700
701 if (!smaster->pushpull)
702 return -EINVAL;
703
704 dev_set_name(&smaster->dev, "siox-%d", smaster->busno);
705
706 smaster->last_poll = jiffies;
707 smaster->poll_thread = kthread_create(siox_poll_thread, smaster,
708 "siox-%d", smaster->busno);
709 if (IS_ERR(smaster->poll_thread)) {
710 smaster->active = 0;
711 return PTR_ERR(smaster->poll_thread);
712 }
713
714 mutex_init(&smaster->lock);
715 INIT_LIST_HEAD(&smaster->devices);
716
717 ret = device_add(&smaster->dev);
718 if (ret)
719 kthread_stop(smaster->poll_thread);
720
721 return ret;
722}
723EXPORT_SYMBOL_GPL(siox_master_register);
724
725void siox_master_unregister(struct siox_master *smaster)
726{
727 /* remove device */
728 device_del(&smaster->dev);
729
730 siox_master_lock(smaster);
731
732 __siox_stop(smaster);
733
734 while (smaster->num_devices) {
735 struct siox_device *sdevice;
736
737 sdevice = container_of(smaster->devices.prev,
738 struct siox_device, node);
739 list_del(&sdevice->node);
740 smaster->num_devices--;
741
742 siox_master_unlock(smaster);
743
744 device_unregister(&sdevice->dev);
745
746 siox_master_lock(smaster);
747 }
748
749 siox_master_unlock(smaster);
750
751 put_device(&smaster->dev);
752}
753EXPORT_SYMBOL_GPL(siox_master_unregister);
754
755static struct siox_device *siox_device_add(struct siox_master *smaster,
756 const char *type, size_t inbytes,
757 size_t outbytes, u8 statustype)
758{
759 struct siox_device *sdevice;
760 int ret;
761 size_t buf_len;
762
763 sdevice = kzalloc(sizeof(*sdevice), GFP_KERNEL);
764 if (!sdevice)
765 return ERR_PTR(-ENOMEM);
766
767 sdevice->type = type;
768 sdevice->inbytes = inbytes;
769 sdevice->outbytes = outbytes;
770 sdevice->statustype = statustype;
771
772 sdevice->smaster = smaster;
773 sdevice->dev.parent = &smaster->dev;
774 sdevice->dev.bus = &siox_bus_type;
775 sdevice->dev.type = &siox_device_type;
776
777 siox_master_lock(smaster);
778
779 dev_set_name(&sdevice->dev, "siox-%d-%d",
780 smaster->busno, smaster->num_devices);
781
782 buf_len = smaster->setbuf_len + inbytes +
783 smaster->getbuf_len + outbytes;
784 if (smaster->buf_len < buf_len) {
785 u8 *buf = krealloc(smaster->buf, buf_len, GFP_KERNEL);
786
787 if (!buf) {
788 dev_err(&smaster->dev,
789 "failed to realloc buffer to %zu\n", buf_len);
790 ret = -ENOMEM;
791 goto err_buf_alloc;
792 }
793
794 smaster->buf_len = buf_len;
795 smaster->buf = buf;
796 }
797
798 ret = device_register(&sdevice->dev);
799 if (ret) {
800 dev_err(&smaster->dev, "failed to register device: %d\n", ret);
801
802 goto err_device_register;
803 }
804
805 smaster->num_devices++;
806 list_add_tail(&sdevice->node, &smaster->devices);
807
808 smaster->setbuf_len += sdevice->inbytes;
809 smaster->getbuf_len += sdevice->outbytes;
810
811 sdevice->status_errors_kn = sysfs_get_dirent(sdevice->dev.kobj.sd,
812 "status_errors");
813 sdevice->watchdog_kn = sysfs_get_dirent(sdevice->dev.kobj.sd,
814 "watchdog");
815 sdevice->watchdog_errors_kn = sysfs_get_dirent(sdevice->dev.kobj.sd,
816 "watchdog_errors");
817 sdevice->connected_kn = sysfs_get_dirent(sdevice->dev.kobj.sd,
818 "connected");
819
820 siox_master_unlock(smaster);
821
822 return sdevice;
823
824err_device_register:
825 /* don't care to make the buffer smaller again */
826
827err_buf_alloc:
828 siox_master_unlock(smaster);
829
830 kfree(sdevice);
831
832 return ERR_PTR(ret);
833}
834
835static void siox_device_remove(struct siox_master *smaster)
836{
837 struct siox_device *sdevice;
838
839 siox_master_lock(smaster);
840
841 if (!smaster->num_devices) {
842 siox_master_unlock(smaster);
843 return;
844 }
845
846 sdevice = container_of(smaster->devices.prev, struct siox_device, node);
847 list_del(&sdevice->node);
848 smaster->num_devices--;
849
850 smaster->setbuf_len -= sdevice->inbytes;
851 smaster->getbuf_len -= sdevice->outbytes;
852
853 if (!smaster->num_devices)
854 __siox_stop(smaster);
855
856 siox_master_unlock(smaster);
857
858 /*
859 * This must be done without holding the master lock because we're
860 * called from device_remove_store which also holds a sysfs mutex.
861 * device_unregister tries to aquire the same lock.
862 */
863 device_unregister(&sdevice->dev);
864}
865
866int __siox_driver_register(struct siox_driver *sdriver, struct module *owner)
867{
868 int ret;
869
870 if (unlikely(!siox_is_registered))
871 return -EPROBE_DEFER;
872
873 if (!sdriver->set_data && !sdriver->get_data) {
874 pr_err("Driver %s doesn't provide needed callbacks\n",
875 sdriver->driver.name);
876 return -EINVAL;
877 }
878
879 sdriver->driver.owner = owner;
880 sdriver->driver.bus = &siox_bus_type;
881
882 if (sdriver->probe)
883 sdriver->driver.probe = siox_driver_probe;
884 if (sdriver->remove)
885 sdriver->driver.remove = siox_driver_remove;
886 if (sdriver->shutdown)
887 sdriver->driver.shutdown = siox_driver_shutdown;
888
889 ret = driver_register(&sdriver->driver);
890 if (ret)
891 pr_err("Failed to register siox driver %s (%d)\n",
892 sdriver->driver.name, ret);
893
894 return ret;
895}
896EXPORT_SYMBOL_GPL(__siox_driver_register);
897
898static int __init siox_init(void)
899{
900 int ret;
901
902 ret = bus_register(&siox_bus_type);
903 if (ret) {
904 pr_err("Registration of SIOX bus type failed: %d\n", ret);
905 return ret;
906 }
907
908 siox_is_registered = true;
909
910 return 0;
911}
912subsys_initcall(siox_init);
913
914static void __exit siox_exit(void)
915{
916 bus_unregister(&siox_bus_type);
917}
918module_exit(siox_exit);
919
920MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
921MODULE_DESCRIPTION("Eckelmann SIOX driver core");
922MODULE_LICENSE("GPL v2");
diff --git a/drivers/siox/siox.h b/drivers/siox/siox.h
new file mode 100644
index 000000000000..c674bf6fb119
--- /dev/null
+++ b/drivers/siox/siox.h
@@ -0,0 +1,49 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2015-2017 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
4 */
5#include <linux/kernel.h>
6#include <linux/kthread.h>
7#include <linux/siox.h>
8
9#define to_siox_master(_dev) container_of((_dev), struct siox_master, dev)
10struct siox_master {
11 /* these fields should be initialized by the driver */
12 int busno;
13 int (*pushpull)(struct siox_master *smaster,
14 size_t setbuf_len, const u8 setbuf[],
15 size_t getbuf_len, u8 getbuf[]);
16
17 /* might be initialized by the driver, if 0 it is set to HZ / 40 */
18 unsigned long poll_interval; /* in jiffies */
19
20 /* framework private stuff */
21 struct mutex lock;
22 bool active;
23 struct module *owner;
24 struct device dev;
25 unsigned int num_devices;
26 struct list_head devices;
27
28 size_t setbuf_len, getbuf_len;
29 size_t buf_len;
30 u8 *buf;
31 u8 status;
32
33 unsigned long last_poll;
34 struct task_struct *poll_thread;
35};
36
37static inline void *siox_master_get_devdata(struct siox_master *smaster)
38{
39 return dev_get_drvdata(&smaster->dev);
40}
41
42struct siox_master *siox_master_alloc(struct device *dev, size_t size);
43static inline void siox_master_put(struct siox_master *smaster)
44{
45 put_device(&smaster->dev);
46}
47
48int siox_master_register(struct siox_master *smaster);
49void siox_master_unregister(struct siox_master *smaster);