Skip to contentSkip to conversation

Introduce the Counter subsystem

PATCH Superseded William Breathitt Gray 4 participants 25 messages Dec 14, 2017 – Feb 23, 2018

Subsystems (3)

v4 of 10 Superseded Latest is v10 →

lore
Share & tools
lore
#0 lore raw

v4 cover Introduce the Counter subsystem

Introduction
============

Apologies for going silent these past couple months just to return with a patchset over 3000 lines larger than the last -- I should have been releasing intermediate versions along the way so shame on me! The Counter system has effectively been rewritten anew, so I believe very little of the code in the previous versions of this patchset remain. However, the Generic Counter paradigm has pretty much remained the same so the theory should be familar. Regardless, I realize I'm dropping off this patchset near the winter holidays so I don't expect a review until well into January -- I'm just releasing this now before I myself head off on an end of year sabbatical.

The most significant difference between this version and the previous, as well as part of the reason for the implementation code changes, is the complete separation of the Generic Counter system from IIO. I decided it was improper to build the Generic Counter system on top of IIO core: it was leading to ugly code, convulted hacks, and forced restrictions on the Generic Counter interface in order to appease the architecture of the IIO system. Most importantly, the IIO core code that was leveraged by the Generic Counter was so minor (essentially just the sysfs attribute support) that it did not justify the extensive hoop-jumping performed to make the code work.

So this patchset introduces the Generic Counter interface without the dependence on IIO code. This now gives the Generic Counter system the freedom to aptly represent counter devices without implementation compatibility concerns regarding other high-level subsystems.

This also makes sense ontologically I believe because whereas the IIO system appears more focused on representing the industrial I/O of a device and their configuration directly, the Generic Counter system is more concerned with the abstract representation of that counter device and the relationships and configurations within which define its operation at a high-level; a counter driver could in theory separately support both the high-level Generic Counter representation of the device as a whole (what are we counting conceptually, how much are we counting, etc.), as well as the low-level IIO representation of the individual inputs and outputs on that device (are the signals differential, do certain signals have current requirements, etc.).

Overview
========

This patchset may be divided into three main groups:

* Generic Counter
* Simple Counter
* Quadrature Counter

Each group begins with a patch introducing the implementation of the interface system, followed afterwards by documentation patches. I recommend reading through the documentation patches first to familiarize your with the interface itself before jumping into the source code for the implementation.

The Simple Counter and Quadrature Counter groups also have example driver code in the dummy-counter and 104-quad-8 patches respectively. The Simple Counter and Quadrature Counter systems themselves being subclasses of the Generic Counter may serve as example driver code for the Generic Counter interface -- though I may end up adding an explicit Generic Counter example in a later patch to the dummy-counter for easier reference.

Since the Generic Counter system no longer depends on IIO, I moved all Counter related source code to the drivers/iio/counter/ directory to keep everything contained together. In addition, with the IIO Kconfig dependency removed, the COUNTER menu appear now appears at the same level as the IIO menu:

        -> Device drivers
          -> Counter Support (COUNTER [=m])

I'm not sure if I should move driver/iio/counter/ to driver/counter/ in order to match the Kconfig heirarchy or to keep it where it is to match the legacy IIO counter location established when we first added the 104-QUAD-8 driver.

Paradigm updates
================

The Generic Counter paradigm has essentially remained the same from the previous patch, but I have made some minor updates. In particular, I've finally settled on a naming convention for the core components of a Counter:

COUNT
-----
A Count represents the count data for a set of Signals. A Count has a count function mode (e.g. "increase" or "quadrature x4") which represents the update behavior for the count data. A Count also has a set of one or more associated Signals.

This component was called "Value" in the previous patches. I believe "Count" is a more direct name for this data, and it also matches how datasheets and people commonly refer to this information in documentation.

SIGNAL
------
A Signal represents a counter input data; this is the data that is typically analyzed by the counter to determine the count data. A Signal may be associated to one or more Counts.

The naming for this component has not changed since the previous patches. I believe "Signal" is a fitting enough name for the input data, as well as matching the common nomenclature for existing counter devices.

SYNAPSE
-------
A Synapse represents the association of a Signal with a respective Count. Signal data affects respective Count data, and the Synapse represents this relationship. The Synapse action mode (e.g. "rising edge" or "double pulse") specifies the Signal data condition which triggers the respective Count's count function evaluation to update the count data. It is possible for the Synapse action mode to be "none" if a Signal is associated with a Count but does not trigger the count function (e.g. the direction signal line for a Pulse-Direction encoding counter).

This component was called "Trigger" in the previous patches. I do not believe "Trigger" was a good name for two main reasons: it could easily be confused for the existing IIO trigger concept, and most importantly it does not convey the connection association aspect of the Count-Signal relationship.

I settled on the "Synapse" name both due to etymology -- from Greek _sunapsis_ meaning "conjunction" -- as well as a biological analogy:
just as neurons connect and fire communication over synapses, so does a Counter Signal connect and fire communication to a Counter Count over a Counter Synapse.

Following the same naming convention and analogy, what was previously called trigger_mode is now known as action_mode, named in reference to action potential -- the condition in a neuron which triggers a fire communication over a synapse, just as a Counter Signal condition specified in the action_mode of a Counter Synapse triggers the count function evaluation for a Counter Count.

Counter classes descriptions
============================

The Generic Counter interface is the most general interface for supporting counter devices; if it qualifies as a Counter, then it can be represented by the Generic Counter interface. Unfortunately, the flexibility of the interface does result in a more cumbersome integration for driver authors: much of the components must be manually configured by the author, which can be a tedious task for large and complex counter devices.

To this end, two subclasses of the Generic Counter interface as introduced in this patchset: the Simple Counter interface, and the Quadrature Counter interface. Both of these interfaces inherit the Generic Counter paradigm, and may be seen as extensions to the interface which restrict the components to a respective specific class of counter devices in order to provide a more apt interface for such devices.

Simple Counter
--------------
Simple Counters are devices that count edge pulses on an input line (e.g. tally counters).

Since the relationship between Signals and Counts is known to be one-to-one, a simple_counter_count structure already contains the associated Signal member for the respective Count. A driver author no longer needs to worry about allocating a separate Signal and Synapse, nor about configuring the association between the respective Count and Signal; the Simple Counter interface abstracts away such details.

Furthermore, since the device type is known, component properties may be further defined and restricted: Count data is a signed integer, Signal data "low" and "high" state is set via enumeration constants, and so are count function and action mode restricted to well-defined "increase"/"decrease" and "none"/"rising edge"/"falling edge"/"both edges" enumeration constants respectively.

Quadrature Counter
------------------
Quadrature Counters are devices that track position based on quadrature pair signals (e.g. rotary encoder counters).

Since the relationship between Signals and Counts is known to be a quadrature pair of Signals to each Count, a quad_counter_count structure already contains the associated Signal members for the respective Count. A driver author no longer needs to worry about allocating separate Signals and Synapses for each quadrature pair, nor about configuring the association between the respective Count and Signals; the Quadrature Counter interface abstracts away such details.

Furthermore, since the device type is known, component properties may be further defined and restricted: Count data is a signed integer, Signal data "low" and "high" state is set via enumeration constants, and so is count function mode restricted to well-defined enumeration constants to represent modes such as "pulse-direction" and "quadrature x4" for example.

Note how driver authors no longer need to interact with Synapses directly when utilizing the Simple Counter and Quadrature Counter interfaces. This should make it easier too for authors to add support since they don't need to fully understand the underlying Counter paradigm in order to take advantage of the interfaces -- just define the Counts and Signals, and they're ready to go.

Even more so, the Quadrature Counter interface takes it a step further and doesn't require action_modes to be explicitly set -- rather they are implicitly determined internally by the system based on the direction and function mode. Abstractions like these should make the Counter interface system as a whole robust enough to handle the diverse classes of counter devices out in the real world.

Compilation warnings
====================

There are three main compilation warnings which pop for this patchset. I've inspected these warnings and none are errors, however they do require some explanation.

* 104-quad-8: warning: enumeration value ‘QUAD_COUNTER_FUNCTION_PULSE_DIRECTION’ not handled in switch

The first warning is rather simple to explain: the QUAD_COUNTER_FUNCTION_PULSE_DIRECTION state is handled by the parent if statement's else condition, so an explicit case condition is not necessary. I can add a default case line to pacify the compiler, but since it would be empty the effort seems frivolous. In some sense as well, a default case may make the switch logic less clear by implying the possibility of additional cases which are not possible in the context of that code path.

* simple-counter: warning: assignment discards ‘const’ qualifier from pointer target type
* quad-counter: warning: assignment discards ‘const’ qualifier from pointer target type

The second warning comes from the mapping of simple_counter_device_ext/quad_counter_device_ext, simple_counter_count_ext/quad_counter_count_ext, and simple_counter_signal_ext/quad_counter_signal_ext to the internal Counter counter_device_ext, counter_count_ext, and counter_signal_ext structures respectively.

The priv member of the counter_device_ext, counter_count_ext, or counter_signal_ext is leveraged to pass the respective simple_counter_device_ext/quad_counter_device_ext, simple_counter_count_ext/quad_counter_count_ext, or simple_counter_signal_ext/quad_counter_signal_ext structure to their respective read/write callback. The priv member is generic on purpose to allow any desired data to be passed; the supplied read/write callbacks should know the datatype of the passed-in priv argument so they cast it appropriately to access their expected data.

As such, the 'const' qualifier of the structures are thus discarded but subsequently cast back when the respective registered callback functions are called. Since this is the intended use case of the priv member -- to generically pass driver data for later recast -- I don't believe this warning needs to be rectified.

* generic-counter: warning: passing argument 5 of ‘counter_attribute_create’ discards ‘const’ qualifier from pointer target type
* generic-counter: warning: passing argument 6 of ‘counter_attribute_create’ discards ‘const’ qualifier from pointer target type

The third warnings comes from a similar situation to the second warning:
a 'const' argument is passed generically via 'void *' for later recast. In this cast, I decided to create a generic function called counter_attribute_create in order to simplify the sysfs attribute registration code in the generic-counter.c file.

The counter_attribute_create function takes in read and write callbacks, as well as two optional generic data arguments to be stored as 'void *' (the component and component_data parameters). Using this setup allows the counter_attribute_create function to be the sole function necessary to create a desired Generic Counter sysfs attribute: read and write callbacks are passed along with relevant Counter component and data generically, which can be cast back later inside those read and write functions to match the expected datatype.

Using a generic counter_attribute_create function reduces duplicate code, but it does result in many superfluous compilation warnings. I can define new attribute_create functions specific to each type of sysfs attribute in order to pacify the warnings, but that seems to be such a waste to increase the amount of code with duplications that are unnecessary. What would you recommend; should I attempt to pacify these warnings or leave them be?

Known TODO items
================

Although I've added the interface documentation files with rst file extensions, I still need to familiarize myself with Sphinx markup constructs to take advantage of the language. For example, I've copied verbatim several structure definitions into the documentation directly, but I believe this would be better left dynamically generated by using the relevant markup syntax. I'll try to clean up the documentation then once I've brushed up on Sphinx.

As noted in a previous patchset version, the signal_write callback should be removed from the interface; there are few if any cases where it makese sense to have a signal_write callback since Signals are always considered inputs in the context of the Counter paradigm.

I've retained the signal_write callback in this version since I'm unsure how to implement the dummy-counter Signal source. Benjamin Gaignard suggested implementing dummy-counter as a gpio-counter which could use gpio to provide a software quadratic counter. Is this the path I should take?

Furthermore, the dummy-counter driver defines its own single platform_device which restricts it to loading only a single instance. I can fix this to allow multiple instances in the next patchset version -- as suggested, I'll check out industrialio-sw-device.c for reference.

Right now the dummy-counter driver only has example code for the Simple Counter interface. It may be prudent to add example code for the Generic Counter and Quadrature Counter interfaces too. I think dummy-counter should serve as the reference driver implementation for all the Counter interfaces, so that driver authors have an example of how to integrate the particular interface they desire.

Finally, I only added very basic support for the Quadrature Counter interface in the 104-QUAD-8 driver. It's possible to support all existing IIO Counter sysfs attributes in the 104-QUAD-8 driver via corresponding quad_counter_device_ext, quad_counter_count_ext, and quad_counter_signal_ext structures, such that only the /sys/bus/counter/devices/counterX/ directory needs to be accessed to interact with the 104-QUAD-8 device. I'll try to add support for those remaining sysfs attributes in the next patchset version.

If I missed anything from the last patchset version review just remind me again and I'll add it to my TODO list. ;)

William Breathitt Gray (11):
iio: Introduce the Generic Counter interface
counter: Documentation: Add Generic Counter sysfs documentation
docs: Add Generic Counter interface documentation
counter: Introduce the Simple Counter interface
counter: Documentation: Add Simple Counter sysfs documentation
docs: Add Simple Counter interface documentation
counter: Add dummy counter driver
counter: Introduce the Quadrature Counter interface
counter: Documentation: Add Quadrature Counter sysfs documentation
docs: Add Quadrature Counter interface documentation
counter: 104-quad-8: Add Quadrature Counter interface support

 .../ABI/testing/sysfs-bus-counter-generic-sysfs    |  73 ++
 .../ABI/testing/sysfs-bus-counter-quadrature-sysfs |  76 ++
 .../ABI/testing/sysfs-bus-counter-simple-sysfs     |  61 ++
 Documentation/driver-api/iio/generic-counter.rst   | 434 +++++++++
 Documentation/driver-api/iio/index.rst             |   3 +
 Documentation/driver-api/iio/quad-counter.rst      | 444 +++++++++
 Documentation/driver-api/iio/simple-counter.rst    | 393 ++++++++
 MAINTAINERS                                        |   9 +
 drivers/iio/Kconfig                                |   3 +-
 drivers/iio/counter/104-quad-8.c                   | 257 +++++-
 drivers/iio/counter/Kconfig                        |  35 +-
 drivers/iio/counter/Makefile                       |   6 +
 drivers/iio/counter/dummy-counter.c                | 308 +++++++
 drivers/iio/counter/generic-counter.c              | 992 +++++++++++++++++++++
 drivers/iio/counter/quad-counter.c                 | 774 ++++++++++++++++
 drivers/iio/counter/simple-counter.c               | 734 +++++++++++++++
 include/linux/iio/counter.h                        | 629 +++++++++++++
 17 files changed, 5216 insertions(+), 15 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-quadrature-sysfs
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs
 create mode 100644 Documentation/driver-api/iio/generic-counter.rst
 create mode 100644 Documentation/driver-api/iio/quad-counter.rst
 create mode 100644 Documentation/driver-api/iio/simple-counter.rst
 create mode 100644 drivers/iio/counter/dummy-counter.c
 create mode 100644 drivers/iio/counter/generic-counter.c
 create mode 100644 drivers/iio/counter/quad-counter.c
 create mode 100644 drivers/iio/counter/simple-counter.c
 create mode 100644 include/linux/iio/counter.h
Signature · 1 line
2.15.1
#1 lore raw

PATCH v4 1/11 iio: Introduce the Generic Counter interface

This patch introduces the Generic Counter interface for supporting counter devices. The Generic Counter interface serves as a catch-all to enable rudimentary support for devices that qualify as counters. More specific and apt counter interfaces may be developed on top of the Generic Counter interface, and those interfaces should be used by drivers where possible rather than the Generic Counter interface directly.

In the context of the Generic Counter interface, a counter is defined as a device that reports one or more "counter counts" based on the state changes of one or more "counter signals" as evaluated by a defined "counter function."

Driver callbacks should be provided to communicate with the device: to read and write various Signals and Counts, and to set and get the "action mode" and "function mode" for various Synapses and Counts respectively.

To support a counter device, a driver must first allocate the available Counter Signals via counter_signal structures. These Signals should be stored as an array and set to the signals array member of an allocated counter_device structure before the Counter is registered to the system.

Counter Counts may be allocated via counter_count structures, and respective Counter Signal associations (Synapses) made via counter_synapse structures. Associated counter_synapse structures are stored as an array and set to the the synapses array member of the respective counter_count structure. These counter_count structures are set to the counts array member of an allocated counter_device structure before the Counter is registered to the system.

A counter device is registered to the system by passing the respective initialized counter_device structure to the counter_register function; similarly, the counter_unregister function unregisters the respective Counter. The devm_counter_register and devm_counter_unregister functions serve as device memory-managed versions of the counter_register and counter_unregister functions respectively.

---
 MAINTAINERS                           |   7 +
 drivers/iio/Kconfig                   |   3 +-
 drivers/iio/counter/Kconfig           |  16 +-
 drivers/iio/counter/Makefile          |   3 +
 drivers/iio/counter/generic-counter.c | 992 ++++++++++++++++++++++++++++++++++
 include/linux/iio/counter.h           | 239 ++++++++
 6 files changed, 1255 insertions(+), 5 deletions(-)
 create mode 100644 drivers/iio/counter/generic-counter.c
 create mode 100644 include/linux/iio/counter.h
MAINTAINERS +7 -0
index 36f76be322a3..07dd7b933bfa 100644
@@ -3661,6 +3661,13 @@ W:	http://www.fi.muni.cz/~kas/cosa/
 S:	Maintained
 F:	drivers/net/wan/cosa*
 
+COUNTER INTERFACE
+M:	William Breathitt Gray <[email protected]>
+L:	[email protected]
+S:	Maintained
+F:	drivers/iio/counter/
+F:	include/linux/iio/counter.h
+
 CPMAC ETHERNET DRIVER
 M:	Florian Fainelli <[email protected]>
 L:	[email protected]
drivers/iio/Kconfig +2 -1
index b3c8c6ef0dff..62a923aeb462 100644
@@ -73,7 +73,6 @@ source "drivers/iio/adc/Kconfig"
 source "drivers/iio/amplifiers/Kconfig"
 source "drivers/iio/chemical/Kconfig"
 source "drivers/iio/common/Kconfig"
-source "drivers/iio/counter/Kconfig"
 source "drivers/iio/dac/Kconfig"
 source "drivers/iio/dummy/Kconfig"
 source "drivers/iio/frequency/Kconfig"
@@ -95,3 +94,5 @@ source "drivers/iio/proximity/Kconfig"
 source "drivers/iio/temperature/Kconfig"
 
 endif # IIO
+
+source "drivers/iio/counter/Kconfig"
drivers/iio/counter/Kconfig +12 -4
index 474e1ac4e7c0..4eaf4e53c5aa 100644
@@ -3,11 +3,18 @@
 #
 # When adding new entries keep the list in alphabetical order
 
-menu "Counters"
+menuconfig COUNTER
+	tristate "Counter support"
+	help
+	  Provides support for Counter devices. The Generic Counter API provides
+	  rudimentary support for counters and serves as building blocks to
+	  create more complex counter interfaces.
+
+if COUNTER
 
 config 104_QUAD_8
 	tristate "ACCES 104-QUAD-8 driver"
-	depends on PC104 && X86 && ISA_BUS_API
+	depends on PC104 && X86 && ISA_BUS_API && IIO
 	help
 	  Say yes here to build support for the ACCES 104-QUAD-8 quadrature
 	  encoder counter/interface device family (104-QUAD-8, 104-QUAD-4).
@@ -23,11 +30,12 @@ config 104_QUAD_8
 
 config STM32_LPTIMER_CNT
 	tristate "STM32 LP Timer encoder counter driver"
-	depends on MFD_STM32_LPTIMER || COMPILE_TEST
+	depends on (MFD_STM32_LPTIMER || COMPILE_TEST) && IIO
 	help
 	  Select this option to enable STM32 Low-Power Timer quadrature encoder
 	  and counter driver.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called stm32-lptimer-cnt.
-endmenu
+
+endif # COUNTER
drivers/iio/counter/Makefile +3 -0
index 1b9a896eb488..513c49d832d4 100644
@@ -4,5 +4,8 @@
 
 # When adding new entries keep the list in alphabetical order
 
+obj-$(CONFIG_COUNTER) += counter.o
+counter-$(CONFIG_COUNTER) += generic-counter.o
+
 obj-$(CONFIG_104_QUAD_8)	+= 104-quad-8.o
 obj-$(CONFIG_STM32_LPTIMER_CNT)	+= stm32-lptimer-cnt.o
drivers/iio/counter/generic-counter.c new file +992 -0

992 lines not on this page · raw message

include/linux/iio/counter.h new file +239 -0

239 lines not on this page · raw message

Signature · 1 line
2.15.1
maintainer
#2 lore raw

Re: [PATCH v4 01/11] iio: Introduce the Generic Counter interface

Quoted 32 lines · On Thu, 14 Dec 2017 15:50:43 -0500 William Breathitt Gray…

This patch introduces the Generic Counter interface for supporting counter devices. The Generic Counter interface serves as a catch-all to enable rudimentary support for devices that qualify as counters. More specific and apt counter interfaces may be developed on top of the Generic Counter interface, and those interfaces should be used by drivers where possible rather than the Generic Counter interface directly.

In the context of the Generic Counter interface, a counter is defined as a device that reports one or more "counter counts" based on the state changes of one or more "counter signals" as evaluated by a defined "counter function."

Driver callbacks should be provided to communicate with the device: to read and write various Signals and Counts, and to set and get the "action mode" and "function mode" for various Synapses and Counts respectively.

To support a counter device, a driver must first allocate the available Counter Signals via counter_signal structures. These Signals should be stored as an array and set to the signals array member of an allocated counter_device structure before the Counter is registered to the system.

Counter Counts may be allocated via counter_count structures, and respective Counter Signal associations (Synapses) made via counter_synapse structures. Associated counter_synapse structures are stored as an array and set to the the synapses array member of the respective counter_count structure. These counter_count structures are set to the counts array member of an allocated counter_device structure before the Counter is registered to the system.

Quoted 6 lines

A counter device is registered to the system by passing the respective initialized counter_device structure to the counter_register function; similarly, the counter_unregister function unregisters the respective Counter. The devm_counter_register and devm_counter_unregister functions serve as device memory-managed versions of the counter_register and counter_unregister functions respectively.

A few minor comments inline but looks basically sound to me.

Jonathan

Quoted 185 lines
---
 MAINTAINERS                           |   7 +
 drivers/iio/Kconfig                   |   3 +-
 drivers/iio/counter/Kconfig           |  16 +-
 drivers/iio/counter/Makefile          |   3 +
 drivers/iio/counter/generic-counter.c | 992 ++++++++++++++++++++++++++++++++++
 include/linux/iio/counter.h           | 239 ++++++++
 6 files changed, 1255 insertions(+), 5 deletions(-)
 create mode 100644 drivers/iio/counter/generic-counter.c
 create mode 100644 include/linux/iio/counter.h
MAINTAINERS +7 -0
index 36f76be322a3..07dd7b933bfa 100644
@@ -3661,6 +3661,13 @@ W:	http://www.fi.muni.cz/~kas/cosa/
 S:	Maintained
 F:	drivers/net/wan/cosa*
 
+COUNTER INTERFACE
+M:	William Breathitt Gray <[email protected]>
+L:	[email protected]
+S:	Maintained
+F:	drivers/iio/counter/
+F:	include/linux/iio/counter.h
+
 CPMAC ETHERNET DRIVER
 M:	Florian Fainelli <[email protected]>
 L:	[email protected]
drivers/iio/Kconfig +2 -1
index b3c8c6ef0dff..62a923aeb462 100644
@@ -73,7 +73,6 @@ source "drivers/iio/adc/Kconfig"
 source "drivers/iio/amplifiers/Kconfig"
 source "drivers/iio/chemical/Kconfig"
 source "drivers/iio/common/Kconfig"
-source "drivers/iio/counter/Kconfig"
 source "drivers/iio/dac/Kconfig"
 source "drivers/iio/dummy/Kconfig"
 source "drivers/iio/frequency/Kconfig"
@@ -95,3 +94,5 @@ source "drivers/iio/proximity/Kconfig"
 source "drivers/iio/temperature/Kconfig"
 
 endif # IIO
+
+source "drivers/iio/counter/Kconfig"
drivers/iio/counter/Kconfig +12 -4
index 474e1ac4e7c0..4eaf4e53c5aa 100644
@@ -3,11 +3,18 @@
 #
 # When adding new entries keep the list in alphabetical order
 
-menu "Counters"
+menuconfig COUNTER
+	tristate "Counter support"
+	help
+	  Provides support for Counter devices. The Generic Counter API provides
+	  rudimentary support for counters and serves as building blocks to
+	  create more complex counter interfaces.
+
+if COUNTER
 
 config 104_QUAD_8
 	tristate "ACCES 104-QUAD-8 driver"
-	depends on PC104 && X86 && ISA_BUS_API
+	depends on PC104 && X86 && ISA_BUS_API && IIO
 	help
 	  Say yes here to build support for the ACCES 104-QUAD-8 quadrature
 	  encoder counter/interface device family (104-QUAD-8, 104-QUAD-4).
@@ -23,11 +30,12 @@ config 104_QUAD_8
 
 config STM32_LPTIMER_CNT
 	tristate "STM32 LP Timer encoder counter driver"
-	depends on MFD_STM32_LPTIMER || COMPILE_TEST
+	depends on (MFD_STM32_LPTIMER || COMPILE_TEST) && IIO
 	help
 	  Select this option to enable STM32 Low-Power Timer quadrature encoder
 	  and counter driver.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called stm32-lptimer-cnt.
-endmenu
+
+endif # COUNTER
drivers/iio/counter/Makefile +3 -0
index 1b9a896eb488..513c49d832d4 100644
@@ -4,5 +4,8 @@
 
 # When adding new entries keep the list in alphabetical order
 
+obj-$(CONFIG_COUNTER) += counter.o
+counter-$(CONFIG_COUNTER) += generic-counter.o
+
 obj-$(CONFIG_104_QUAD_8)	+= 104-quad-8.o
 obj-$(CONFIG_STM32_LPTIMER_CNT)	+= stm32-lptimer-cnt.o
drivers/iio/counter/generic-counter.c new file +77 -0
new file mode 100644
index 000000000000..0efd36ee2118
@@ -0,0 +1,992 @@
+/*
+ * Generic Counter interface
+ * Copyright (C) 2017 William Breathitt Gray
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/gfp.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/kdev_t.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#include <linux/iio/counter.h>
+
+struct counter_device_attr {
+	struct device_attribute		dev_attr;
+	struct list_head		l;
+	void				*component;
+	void				*component_data;
+};
+
+static int counter_attribute_create(const char *const prefix,
+	const char *const name,
+	ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+		char *buf),
+	ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t len),
+	void *const component, void *const component_data,
+	struct counter_device_state *const device_state)
+{
+	struct counter_device_attr *counter_attr;
+	struct device_attribute *dev_attr;
+	struct counter_device_attr *t;
+	int err;
+	struct list_head *const attr_list = &device_state->attr_list;
+
+	/* Allocate a Counter device attribute */
+	counter_attr = kzalloc(sizeof(*counter_attr), GFP_KERNEL);
+	if (!counter_attr)
+		return -ENOMEM;
+	dev_attr = &counter_attr->dev_attr;
+
+	sysfs_attr_init(&dev_attr->attr);
+
+	/* Configure device attribute */
+	dev_attr->attr.name = kasprintf(GFP_KERNEL, "%s%s", prefix, name);
+	if (!dev_attr->attr.name) {
+		err = -ENOMEM;
+		goto err_free_counter_attr;
+	}
+	if (show) {
+		dev_attr->attr.mode |= 0444;
+		dev_attr->show = show;
+	}
+	if (store) {
+		dev_attr->attr.mode |= 0200;
+		dev_attr->store = store;
+	}

drivers/iio/counter/generic-counter.c line 87

Quoted 10 lines
drivers/iio/counter/generic-counter.c new file +10 -0
+
+	/* Check for duplicate name */
+	list_for_each_entry(t, attr_list, l)
+		if (!strcmp(t->dev_attr.attr.name, dev_attr->attr.name)) {
+			dev_err(&device_state->dev,
+				"tried to double register : %s\n",
+				t->dev_attr.attr.name);
+			err = -EBUSY;
+			goto err_free_attr_name;
+		}

I think there is no actual need to deal with the duplicate here. It will cause an error when the sysfs attributes are actually created. I'd leave it until there to run this sanity check as this represents a bug anyway so no real need to check for it early.

Quoted 568 lines
drivers/iio/counter/generic-counter.c new file +568 -0
+
+	/* Store associated Counter component with attribute */
+	counter_attr->component = component;
+	counter_attr->component_data = component_data;
+
+	/* Keep track of the attribute for later cleanup */
+	list_add(&counter_attr->l, attr_list);
+	device_state->num_attr++;
+
+	return 0;
+
+err_free_attr_name:
+	kfree(dev_attr->attr.name);
+err_free_counter_attr:
+	kfree(counter_attr);
+	return err;
+}
+
+#define to_counter_attr(_dev_attr) \
+	container_of(_dev_attr, struct counter_device_attr, dev_attr)
+
+static ssize_t counter_signal_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct counter_device *const counter = dev_get_drvdata(dev);
+	struct counter_signal *const signal = to_counter_attr(attr)->component;
+
+	return counter->signal_read(counter, signal, buf);
+}
+
+static ssize_t counter_signal_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct counter_device *const counter = dev_get_drvdata(dev);
+	struct counter_signal *const signal = to_counter_attr(attr)->component;
+
+	return counter->signal_write(counter, signal, buf, len);
+}
+
+static ssize_t counter_device_attr_name_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	const char *const name = to_counter_attr(attr)->component;
+
+	return scnprintf(buf, PAGE_SIZE, "%s\n", name);
+}
+
+static ssize_t counter_signal_ext_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	const struct counter_device_attr *const devattr = to_counter_attr(attr);
+	const struct counter_signal_ext *const ext = devattr->component_data;
+	struct counter_device *const counter = dev_get_drvdata(dev);
+	struct counter_signal *const signal = devattr->component;
+
+	return ext->read(counter, signal, ext->priv, buf);
+}
+
+static ssize_t counter_signal_ext_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	const struct counter_device_attr *const devattr = to_counter_attr(attr);
+	const struct counter_signal_ext *const ext = devattr->component_data;
+	struct counter_device *const counter = dev_get_drvdata(dev);
+	struct counter_signal *const signal = devattr->component;
+
+	return ext->write(counter, signal, ext->priv, buf, len);
+}
+
+static int counter_signal_ext_register(const char *const prefix,
+	struct counter_signal *const signal,
+	struct counter_device_state *const device_state)
+{
+	const size_t num_ext = signal->num_ext;
+	size_t i;
+	const struct counter_signal_ext *ext;
+	int err;
+
+	/* Return early if no extensions */
+	if (!signal->ext || !num_ext)
+		return 0;
+
+	/* Create an attribute for each extension */
+	for (i = 0 ; i < num_ext; i++) {
+		ext = signal->ext + i;
+		err = counter_attribute_create(prefix, ext->name,
+			(ext->read) ? counter_signal_ext_show : NULL,
+			(ext->write) ? counter_signal_ext_store : NULL,
+			signal, ext, device_state);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int counter_signal_attributes_create(const char *const signal_attr_name,
+	const struct counter_device *const counter,
+	struct counter_signal *const signal)
+{
+	struct counter_device_state *const device_state = counter->device_state;
+	int err;
+	const char *prefix;
+
+	/* Create main Signal attribute */
+	err = counter_attribute_create("", signal_attr_name,
+		(counter->signal_read) ? counter_signal_show : NULL,
+		(counter->signal_write) ? counter_signal_store : NULL,
+		signal, NULL, device_state);
+	if (err)
+		return err;
+
+	prefix = kasprintf(GFP_KERNEL, "%s_", signal_attr_name);
+	if (!prefix)
+		return -ENOMEM;
+
+	/* Create Signal name attribute */
+	if (signal->name) {
+		err = counter_attribute_create(prefix, "name",
+			counter_device_attr_name_show, NULL, signal->name, NULL,
+			device_state);
+		if (err)
+			goto err_free_prefix;
+	}
+
+	/* Register Signal extension attributes */
+	err = counter_signal_ext_register(prefix, signal, device_state);
+	if (err)
+		goto err_free_prefix;
+
+	kfree(prefix);
+
+	return 0;
+
+err_free_prefix:
+	kfree(prefix);
+	return err;
+}
+
+static int counter_signals_register(const struct counter_device *const counter)
+{
+	const size_t num_signals = counter->num_signals;
+	struct counter_device_state *const device_state = counter->device_state;
+	struct device *const dev = &device_state->dev;
+	size_t i;
+	struct counter_signal *signal;
+	const char *name;
+	int err;
+
+	/* At least one Signal must be defined */
+	if (!counter->signals || !num_signals) {
+		dev_err(dev, "Signals undefined\n");
+		return -EINVAL;
+	}
+
+	/* Register each Signal */
+	for (i = 0; i < num_signals; i++) {
+		signal = counter->signals + i;
+
+		/* Generate Signal attribute name */
+		name = kasprintf(GFP_KERNEL, "signal%d", signal->id);
+		if (!name)
+			return -ENOMEM;
+
+		/* Create all attributes associated with Signal */
+		err = counter_signal_attributes_create(name, counter, signal);
+		if (err)
+			goto err_free_name;
+
+		kfree(name);
+	}
+
+	return 0;
+
+err_free_name:
+	kfree(name);
+	return err;
+}
+
+static ssize_t counter_action_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	const struct counter_device_attr *const devattr = to_counter_attr(attr);
+	int err;
+	struct counter_device *const counter = dev_get_drvdata(dev);
+	struct counter_count *const count = devattr->component_data;
+	struct counter_synapse *const synapse = devattr->component;
+	size_t action;
+
+	err = counter->action_get(counter, count, synapse, &action);
+	if (err)
+		return err;
+
+	synapse->action = action;
+
+	return scnprintf(buf, PAGE_SIZE, "%s\n", synapse->actions[action]);
+}
+
+static ssize_t counter_action_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	const struct counter_device_attr *const devattr = to_counter_attr(attr);
+	struct counter_synapse *const synapse = devattr->component;
+	size_t action;
+	const size_t num_actions = synapse->num_actions;
+	int err;
+	struct counter_device *const counter = dev_get_drvdata(dev);
+	struct counter_count *const count = devattr->component_data;
+
+	/* Find requested action mode */
+	for (action = 0; action < num_actions; action++)
+		if (sysfs_streq(buf, synapse->actions[action]))
+			break;
+	/* If requested action mode not found */
+	if (action >= num_actions)
+		return -EINVAL;
+
+	err = counter->action_set(counter, count, synapse, action);
+	if (err)
+		return err;
+
+	synapse->action = action;
+
+	return len;
+}
+
+static ssize_t counter_device_attr_available_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	const struct counter_device_attr *const devattr = to_counter_attr(attr);
+	const char *const *const modes = devattr->component;
+	const size_t num_modes = *(size_t *)devattr->component_data;
+	ssize_t len = 0;
+	size_t i;
+
+	for (i = 0; i < num_modes; i++)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", modes[i]);
+
+	return len;
+}
+
+static int counter_synapses_register(const struct counter_device *const counter,
+	struct counter_count *const count, const char *const count_attr_name)
+{
+	struct counter_device_state *const device_state = counter->device_state;
+	const size_t num_synapses = count->num_synapses;
+	struct device *const dev = &device_state->dev;
+	size_t i;
+	struct counter_synapse *synapse;
+	const char *prefix;
+	int err;
+
+	/* At least one Synapse must be defined */
+	if (!count->synapses || !num_synapses) {
+		dev_err(dev, "Count '%d' Synapses undefined\n",	count->id);
+		return -EINVAL;
+	}
+
+	/* Register each Synapse */
+	for (i = 0; i < num_synapses; i++) {
+		synapse = count->synapses + i;
+
+		/* Ensure all Synapses have a defined Signal */
+		if (!synapse->signal) {
+			dev_err(dev,
+				"Count '%d' Synapse '%zu' Signal undefined\n",
+				count->id, i);
+			return -EINVAL;
+		}
+
+		/* At least one action mode must be defined for each Synapse */
+		if (!synapse->actions || !synapse->num_actions) {
+			dev_err(dev,
+				"Count '%d' Signal '%d' action modes undefined\n",
+				count->id, synapse->signal->id);
+			return -EINVAL;
+		}
+
+		/* Generate attribute prefix */
+		prefix = kasprintf(GFP_KERNEL, "%s_signal%d_", count_attr_name,
+			synapse->signal->id);
+		if (!prefix)
+			return -ENOMEM;
+
+		/* Create action attribute */
+		err = counter_attribute_create(prefix, "action",
+			(counter->action_get) ? counter_action_show : NULL,
+			(counter->action_set) ? counter_action_store : NULL,
+			synapse, count, device_state);
+		if (err)
+			goto err_free_prefix;
+
+		/* Create action_available attribute */
+		err = counter_attribute_create(prefix, "action_available",
+			counter_device_attr_available_show, NULL,
+			synapse->actions, &synapse->num_actions, device_state);
+		if (err)
+			goto err_free_prefix;
+
+		kfree(prefix);
+	}
+
+	return 0;
+
+err_free_prefix:
+	kfree(prefix);
+	return err;
+}
+
+static ssize_t counter_count_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct counter_device *const counter = dev_get_drvdata(dev);
+	struct counter_count *const count = to_counter_attr(attr)->component;
+
+	return counter->count_read(counter, count, buf);
+}
+
+static ssize_t counter_count_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct counter_device *const counter = dev_get_drvdata(dev);
+	struct counter_count *const count = to_counter_attr(attr)->component;
+
+	return counter->count_write(counter, count, buf, len);
+}
+
+static ssize_t counter_function_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	int err;
+	struct counter_device *const counter = dev_get_drvdata(dev);
+	struct counter_count *const count = to_counter_attr(attr)->component;
+	size_t function;
+
+	err = counter->function_get(counter, count, &function);
+	if (err)
+		return err;
+
+	count->function = function;
+
+	return scnprintf(buf, PAGE_SIZE, "%s\n", count->functions[function]);
+}
+
+static ssize_t counter_function_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct counter_count *const count = to_counter_attr(attr)->component;
+	const size_t num_functions = count->num_functions;
+	size_t function;
+	int err;
+	struct counter_device *const counter = dev_get_drvdata(dev);
+
+	/* Find requested Count function mode */
+	for (function = 0; function < num_functions; function++)
+		if (sysfs_streq(buf, count->functions[function]))
+			break;
+	/* Return error if requested Count function mode not found */
+	if (function >= num_functions)
+		return -EINVAL;
+
+	err = counter->function_set(counter, count, function);
+	if (err)
+		return err;
+
+	count->function = function;
+
+	return len;
+}
+
+static ssize_t counter_count_synapses_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	size_t i;
+	struct counter_count *const count = to_counter_attr(attr)->component;
+	const struct counter_synapse *synapse;
+	ssize_t len = 0;
+
+	/* Print out a list of every Signal association to Count */
+	for (i = 0; i < count->num_synapses; i++) {
+		synapse = count->synapses + i;
+		len += snprintf(buf + len, PAGE_SIZE - len, "%d\t%s\t%s\n",
+			synapse->signal->id, synapse->signal->name,
+			synapse->actions[synapse->action]);
+		if (len >= PAGE_SIZE)
+			return -ENOMEM;
+	}
+
+	return len;
+}
+
+static ssize_t counter_count_ext_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	const struct counter_device_attr *const devattr = to_counter_attr(attr);
+	const struct counter_count_ext *const ext = devattr->component_data;
+	struct counter_device *const counter = dev_get_drvdata(dev);
+	struct counter_count *const count = devattr->component;
+
+	return ext->read(counter, count, ext->priv, buf);
+}
+
+static ssize_t counter_count_ext_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	const struct counter_device_attr *const devattr = to_counter_attr(attr);
+	const struct counter_count_ext *const ext = devattr->component_data;
+	struct counter_device *const counter = dev_get_drvdata(dev);
+	struct counter_count *const count = devattr->component;
+
+	return ext->write(counter, count, ext->priv, buf, len);
+}
+
+static int counter_count_ext_register(const char *const prefix,
+	struct counter_count *const count,
+	struct counter_device_state *const device_state)
+{
+	const size_t num_ext = count->num_ext;
+	size_t i;
+	const struct counter_count_ext *ext;
+	int err;
+
+	/* Return early if no extensions */
+	if (!count->ext || !num_ext)
+		return 0;
+
+	/* Create an attribute for each extension */
+	for (i = 0 ; i < num_ext; i++) {
+		ext = count->ext + i;
+		err = counter_attribute_create(prefix, ext->name,
+			(ext->read) ? counter_count_ext_show : NULL,
+			(ext->write) ? counter_count_ext_store : NULL,
+			count, ext, device_state);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int counter_count_attributes_create(const char *const count_attr_name,
+	const struct counter_device *const counter,
+	struct counter_count *const count)
+{
+	struct counter_device_state *const device_state = counter->device_state;
+	int err;
+	const char *prefix;
+
+	/* Create main Count attribute */
+	err = counter_attribute_create("", count_attr_name,
+		(counter->count_read) ? counter_count_show : NULL,
+		(counter->count_write) ? counter_count_store : NULL,
+		count, NULL, device_state);
+	if (err)
+		return err;
+
+	prefix = kasprintf(GFP_KERNEL, "%s_", count_attr_name);
+	if (!prefix)
+		return -ENOMEM;
+
+	/* Create Count function attribute */
+	err = counter_attribute_create(prefix, "function",
+		(counter->function_get) ? counter_function_show : NULL,
+		(counter->function_set) ? counter_function_store : NULL,
+		count, NULL, device_state);
+	if (err)
+		goto err_free_prefix;
+
+	/* Create Count function_available attribute */
+	err = counter_attribute_create(prefix, "function_available",
+		counter_device_attr_available_show, NULL, count->functions,
+		&count->num_functions, device_state);
+	if (err)
+		goto err_free_prefix;
+
+	/* Create Count synapses attribute */
+	err = counter_attribute_create(prefix, "synapses",
+		counter_count_synapses_show, NULL, count, NULL, device_state);
+	if (err)
+		goto err_free_prefix;
+
+	/* Create Count name attribute */
+	if (count->name) {
+		err = counter_attribute_create(prefix, "name",
+			counter_device_attr_name_show,	NULL, count->name, NULL,
+			device_state);
+		if (err)
+			goto err_free_prefix;
+	}
+
+	/* Register Count extension attributes */
+	err = counter_count_ext_register(prefix, count, device_state);
+	if (err)
+		goto err_free_prefix;
+
+	kfree(prefix);
+
+	return 0;
+
+err_free_prefix:
+	kfree(prefix);
+	return err;
+}
+
+static int counter_counts_register(const struct counter_device *const counter)
+{
+	const size_t num_counts = counter->num_counts;
+	struct device *const dev = &counter->device_state->dev;
+	size_t i;
+	struct counter_count *count;
+	const char *name;
+	int err;
+
+	/* At least one Count must be defined */
+	if (!counter->counts || !num_counts) {
+		dev_err(dev, "Counts undefined\n");
+		return -EINVAL;
+	}
+
+	/* Register each Count */
+	for (i = 0; i < num_counts; i++) {
+		count = counter->counts + i;
+
+		/* At least one function mode must be defined for each Count */
+		if (!count->functions || !count->num_functions) {
+			dev_err(dev, "Count '%d' function modes undefined\n",
+				count->id);
+			return -EINVAL;
+		}
+
+		/* Generate attribute name */
+		name = kasprintf(GFP_KERNEL, "count%d", count->id);
+		if (!name)
+			return -ENOMEM;
+
+		/* Register the Synapses associated with each Count */
+		err = counter_synapses_register(counter, count, name);
+		if (err)
+			goto err_free_name;
+
+		/* Create all attributes associated with Count */
+		err = counter_count_attributes_create(name, counter, count);
+		if (err)
+			goto err_free_name;
+
+		kfree(name);
+	}
+
+	return 0;
+
+err_free_name:
+	kfree(name);
+	return err;
+}
+
+static struct bus_type counter_bus_type = {
+	.name = "counter"
+};
+
+static dev_t counter_devt;
+
+#define COUNTER_DEV_MAX 256
+
+static int __init counter_init(void)
+{
+	int err;
+
+	err = bus_register(&counter_bus_type);

drivers/iio/counter/generic-counter.c line 665

Quoted 10 lines
drivers/iio/counter/generic-counter.c new file +10 -0
+	if (err) {
+		pr_err("counter: could not register Counter bus type\n");
+		return err;
+	}
+
+	err = alloc_chrdev_region(&counter_devt, 0, COUNTER_DEV_MAX, "counter");
+	if (err) {
+		pr_err("counter: failed to allocate char dev region\n");
+		bus_unregister(&counter_bus_type);
+		return err;

Drop this and return err below

Quoted 201 lines
drivers/iio/counter/generic-counter.c new file +201 -0
+	}
+
+	return 0;
+}
+
+static void __exit counter_exit(void)
+{
+	if (counter_devt)
+		unregister_chrdev_region(counter_devt, COUNTER_DEV_MAX);
+	bus_unregister(&counter_bus_type);
+}
+
+static void free_counter_device_state_attr_list(struct list_head *attr_list)
+{
+	struct counter_device_attr *p, *n;
+
+	list_for_each_entry_safe(p, n, attr_list, l) {
+		kfree(p->dev_attr.attr.name);
+		list_del(&p->l);
+		kfree(p);
+	}
+}
+
+/* Provides a unique ID for each counter device */
+static DEFINE_IDA(counter_ida);
+
+static void counter_device_release(struct device *dev)
+{
+	struct counter_device *const counter = dev_get_drvdata(dev);
+	struct counter_device_state *const device_state = counter->device_state;
+
+	kfree(device_state->attr_group.attrs);
+	free_counter_device_state_attr_list(&device_state->attr_list);
+	ida_simple_remove(&counter_ida, device_state->id);
+	kfree(device_state);
+}
+
+static struct device_type counter_device_type = {
+	.name = "counter_device",
+	.release = counter_device_release
+};
+
+static int counter_chrdev_open(struct inode *inode, struct file *filp)
+{
+	struct counter_device_state *const device_state = container_of(
+		inode->i_cdev, struct counter_device_state, chrdev);
+	struct device *const dev = &device_state->dev;
+	struct counter_device *const counter = dev_get_drvdata(dev);
+
+	get_device(dev);
+	filp->private_data = counter;
+
+	return 0;
+}
+
+static int counter_chrdev_release(struct inode *inode, struct file *filp)
+{
+	struct counter_device_state *const device_state = container_of(
+		inode->i_cdev, struct counter_device_state, chrdev);
+
+	put_device(&device_state->dev);
+
+	return 0;
+}
+
+static const struct file_operations counter_fileops = {
+	.owner = THIS_MODULE,
+	.open = counter_chrdev_open,
+	.release = counter_chrdev_release
+};
+
+static ssize_t counter_device_ext_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	const struct counter_device_attr *const devattr = to_counter_attr(attr);
+	const struct counter_device_ext *const ext = devattr->component_data;
+	struct counter_device *const counter = dev_get_drvdata(dev);
+
+	return ext->read(counter, ext->priv, buf);
+}
+
+static ssize_t counter_device_ext_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	const struct counter_device_attr *const devattr = to_counter_attr(attr);
+	const struct counter_device_ext *const ext = devattr->component_data;
+	struct counter_device *const counter = dev_get_drvdata(dev);
+
+	return ext->write(counter, ext->priv, buf, len);
+}
+
+static int counter_device_ext_register(struct counter_device *const counter)
+{
+	const size_t num_ext = counter->num_ext;
+	size_t i;
+	const struct counter_device_ext *ext;
+	int err;
+
+	/* Return early if no extensions */
+	if (!counter->ext || !num_ext)
+		return 0;
+
+	/* Create an attribute for each extension */
+	for (i = 0 ; i < num_ext; i++) {
+		ext = counter->ext + i;
+		err = counter_attribute_create("", ext->name,
+			(ext->read) ? counter_device_ext_show : NULL,
+			(ext->write) ? counter_device_ext_store : NULL,
+			NULL, ext, counter->device_state);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static ssize_t counter_name_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	const struct counter_device *const counter = dev_get_drvdata(dev);
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", counter->name);
+}
+
+static DEVICE_ATTR_RO(counter_name);
+
+/**
+ * counter_register - register Counter to the system
+ * @counter: pointer to Counter to register
+ *
+ * This function registers a Counter to the system. A sysfs "counter" directory
+ * will be created and populated with sysfs attributes correlating with the
+ * Counter Signals, Synapses, and Counts respectively.
+ */
+int counter_register(struct counter_device *const counter)
+{
+	int err;
+	struct counter_device_state *device_state;
+	struct counter_device_attr *p;
+	size_t i = 0;
+
+	if (!counter)
+		return -EINVAL;
+
+	/* Allocate internal state container for Counter device */
+	device_state = kzalloc(sizeof(*device_state), GFP_KERNEL);
+	if (!device_state)
+		return -ENOMEM;
+	counter->device_state = device_state;
+
+	/* Acquire unique ID */
+	device_state->id = ida_simple_get(&counter_ida, 0, 0, GFP_KERNEL);
+	if (device_state->id < 0) {
+		err = device_state->id;
+		goto err_free_device_state;
+	}
+
+	/* Configure device structure for Counter */
+	device_state->dev.type = &counter_device_type;
+	device_state->dev.bus = &counter_bus_type;
+	if (counter->parent) {
+		device_state->dev.parent = counter->parent;
+		device_state->dev.of_node = counter->parent->of_node;
+	}
+	dev_set_name(&device_state->dev, "counter%d", device_state->id);
+	device_initialize(&device_state->dev);
+	dev_set_drvdata(&device_state->dev, counter);
+	device_state->dev.devt = MKDEV(MAJOR(counter_devt), device_state->id);
+
+	/* Initialize attribute list */
+	INIT_LIST_HEAD(&device_state->attr_list);
+
+	/* Verify Signals are valid and register */
+	err = counter_signals_register(counter);
+	if (err)
+		goto err_free_attributes;
+
+	/* Verify Counts and respective Synapses are valid and register */
+	err = counter_counts_register(counter);
+	if (err)
+		goto err_free_attributes;
+
+	/* Register Counter device extension attributes */
+	err = counter_device_ext_register(counter);
+	if (err)
+		goto err_free_attributes;
+
+	/* Account for name attribute */
+	if (counter->name)
+		device_state->num_attr++;
+
+	/* Allocate space for attribute pointers in attribute group */
+	device_state->attr_group.attrs = kcalloc(device_state->num_attr + 1,
+		sizeof(*device_state->attr_group.attrs), GFP_KERNEL);
+	if (!device_state->attr_group.attrs) {
+		err = -ENOMEM;
+		goto err_free_attributes;
+	}
+
+	/* Add attribute pointers to attribute group */
+	list_for_each_entry(p, &device_state->attr_list, l)

drivers/iio/counter/generic-counter.c line 876

Quoted 10 lines
drivers/iio/counter/generic-counter.c new file +10 -0
+		device_state->attr_group.attrs[i++] = &p->dev_attr.attr;
+	if (counter->name)
+		device_state->attr_group.attrs[i] = &dev_attr_counter_name.attr;
+
+	/* Associate attributes with device */
+	device_state->groups[0] = &device_state->attr_group;
+	device_state->dev.groups = device_state->groups;
+
+	/* Initialize associated character device */
+	cdev_init(&device_state->chrdev, &counter_fileops);

Right now you can open and close it but nothing else. I'd get rid of the cdev entirely unless I'm missing a later use.

Quoted 209 lines
drivers/iio/counter/generic-counter.c new file +116 -0
+	device_state->chrdev.owner = THIS_MODULE;
+	err = cdev_device_add(&device_state->chrdev, &device_state->dev);
+	if (err)
+		goto err_free_attr_group_attrs;
+
+	return 0;
+
+err_free_attr_group_attrs:
+	kfree(counter->device_state->attr_group.attrs);
+err_free_attributes:
+	free_counter_device_state_attr_list(&counter->device_state->attr_list);
+	ida_simple_remove(&counter_ida, counter->device_state->id);
+err_free_device_state:
+	kfree(counter->device_state);
+	return err;
+}
+EXPORT_SYMBOL(counter_register);
+
+/**
+ * counter_unregister - unregister Counter from the system
+ * @counter: pointer to Counter to unregister
+ *
+ * The Counter is unregistered from the system; all allocated memory is freed.
+ */
+void counter_unregister(struct counter_device *const counter)
+{
+	struct cdev *cdev;
+	struct device *dev;
+
+	if (counter) {
+		cdev = &counter->device_state->chrdev;
+		dev = &counter->device_state->dev;
+
+		cdev_device_del(cdev, dev);
+		put_device(dev);
+	}
+}
+EXPORT_SYMBOL(counter_unregister);
+
+static void devm_counter_unreg(struct device *dev, void *res)
+{
+	counter_unregister(*(struct counter_device **)res);
+}
+
+/**
+ * devm_counter_register - Resource-managed counter_register
+ * @dev: device to allocate counter_device for
+ * @counter: pointer to Counter to register
+ *
+ * Managed counter_register. The Counter registered with this function is
+ * automatically unregistered on driver detach. This function calls
+ * counter_register internally. Refer to that function for more information.
+ *
+ * If an Counter registered with this function needs to be unregistered
+ * separately, devm_counter_unregister must be used.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int devm_counter_register(struct device *dev,
+	struct counter_device *const counter)
+{
+	struct counter_device **ptr;
+	int ret;
+
+	ptr = devres_alloc(devm_counter_unreg, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+
+	ret = counter_register(counter);
+	if (!ret) {
+		*ptr = counter;
+		devres_add(dev, ptr);
+	} else
+		devres_free(ptr);
+
+	return ret;
+}
+EXPORT_SYMBOL(devm_counter_register);
+
+static int devm_counter_match(struct device *dev, void *res, void *data)
+{
+	struct counter_device **r = res;
+
+	if (!r || !*r) {
+		WARN_ON(!r || !*r);
+		return 0;
+	}
+
+	return *r == data;
+}
+
+/**
+ * devm_counter_unregister - Resource-managed counter_unregister
+ * @dev: device this counter_device belongs to
+ * @counter: the Counter associated with the device
+ *
+ * Unregister Counter registered with devm_counter_register.
+ */
+void devm_counter_unregister(struct device *dev,
+	struct counter_device *const counter)
+{
+	int rc;
+
+	rc = devres_release(dev, devm_counter_unreg,
+		devm_counter_match, counter);
+	WARN_ON(rc);
+}
+EXPORT_SYMBOL(devm_counter_unregister);
+
+subsys_initcall(counter_init);
+module_exit(counter_exit);
+
+MODULE_AUTHOR("William Breathitt Gray <[email protected]>");
+MODULE_DESCRIPTION("Generic Counter interface");
+MODULE_LICENSE("GPL v2");
include/linux/iio/counter.h new file +87 -0
new file mode 100644
index 000000000000..070ed8fd53fb
@@ -0,0 +1,239 @@
+/*
+ * Counter interface
+ * Copyright (C) 2017 William Breathitt Gray
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#ifndef _COUNTER_H_
+#define _COUNTER_H_
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+struct counter_device;
+struct counter_signal;
+
+/**
+ * struct counter_signal_ext - Counter Signal extensions
+ * @name:	[DRIVER] attribute name
+ * @read:	[DRIVER] read callback for this attribute; may be NULL
+ * @write:	[DRIVER] write callback for this attribute; may be NULL
+ * @priv:	[DRIVER] data private to the driver
+ */
+struct counter_signal_ext {
+	const char	*name;
+	ssize_t		(*read)(struct counter_device *counter,
+				struct counter_signal *signal, void *priv,
+				char *buf);
+	ssize_t		(*write)(struct counter_device *counter,
+				struct counter_signal *signal, void *priv,
+				const char *buf, size_t len);
+	void		*priv;
+};
+
+/**
+ * struct counter_signal - Counter Signal node
+ * @id:		[DRIVER] unique ID used to identify signal
+ * @name:	[DRIVER] device-specific signal name
+ * @ext:	[DRIVER] optional array of Counter Signal extensions
+ * @num_ext:	[DRIVER] number of Counter Signal extensions specified in @ext
+ * @priv:	[DRIVER] optional private data supplied by driver
+ */
+struct counter_signal {
+	int		id;
+	const char	*name;
+
+	const struct counter_signal_ext	*ext;
+	size_t				num_ext;
+
+	void	*priv;
+};
+
+/**
+ * struct counter_synapse - Counter Synapse node
+ * @action:		[DRIVER] current action mode
+ * @actions:		[DRIVER] available action modes
+ * @num_actions:	[DRIVER] number of action modes specified in @actions
+ * @signal:		[DRIVER] pointer to associated signal
+ */
+struct counter_synapse {
+	size_t			action;
+	const char *const	*actions;
+	size_t			num_actions;
+	struct counter_signal	*signal;
+};
+
+struct counter_count;
+
+/**
+ * struct counter_count_ext - Counter Count extension
+ * @name:	[DRIVER] attribute name
+ * @read:	[DRIVER] read callback for this attribute; may be NULL
+ * @write:	[DRIVER] write callback for this attribute; may be NULL
+ * @priv:	[DRIVER] data private to the driver
+ */
+struct counter_count_ext {
+	const char	*name;
+	ssize_t		(*read)(struct counter_device *counter,
+				struct counter_count *count, void *priv,

include/linux/iio/counter.h line 97

Quoted 10 lines
include/linux/iio/counter.h new file +10 -0
+				char *buf);
+	ssize_t		(*write)(struct counter_device *counter,
+				struct counter_count *count, void *priv,
+				const char *buf, size_t len);
+	void		*priv;
+};
+
+/**
+ * struct counter_count - Counter Count node
+ * @id:			[DRIVER] unique ID used to identify Count

Again, drop [DRIVER]

include/linux/iio/counter.h line 110

Quoted 13 lines
include/linux/iio/counter.h new file +13 -0
+ * @name:		[DRIVER] device-specific Count name
+ * @function:		[DRIVER] current function mode
+ * @functions:		[DRIVER] available function modes
+ * @num_functions:	[DRIVER] number of functions specified in @functions
+ * @synapses:		[DRIVER] array of synapses for initialization
+ * @num_synapses:	[DRIVER] number of synapses specified in @synapses
+ * @ext:		[DRIVER] optional array of Counter Count extensions
+ * @num_ext:		[DRIVER] number of Counter Count extensions specified in
+ *			@ext
+ * @priv:		[DRIVER] optional private data supplied by driver
+ */
+struct counter_count {
+	int			id;

My personal view is that trying to align these always just leads to it going wrong. I'd not do it, but it is personal taste so up to you!

Quoted 18 lines
include/linux/iio/counter.h new file +18 -0
+	const char		*name;
+	size_t			function;
+	const char *const	*functions;
+	size_t			num_functions;
+
+	struct counter_synapse	*synapses;
+	size_t			num_synapses;
+
+	const struct counter_count_ext	*ext;
+	size_t				num_ext;
+
+	void	*priv;
+};
+
+/**
+ * struct counter_device_state - internal state container for a Counter device
+ * @id:		unique ID used to identify the Counter
+ * @dev:	internal device structure

include/linux/iio/counter.h line 138

Quoted 10 lines
include/linux/iio/counter.h new file +10 -0
+ * @chrdev:	associated character device
+ * @attr_list:	list to keep track of created Counter sysfs attributes
+ * @attr_group:	Counter sysfs attributes group
+ * @groups:	attribute groups
+ * @num_attr:	number of Counter sysfs attributes
+ */
+struct counter_device_state {
+	int				id;
+	struct device			dev;
+	struct cdev			chrdev;

So far in the description I haven't seen any use of a chrdev. Perhaps it will become clear later!

include/linux/iio/counter.h line 141

Quoted 3 lines
include/linux/iio/counter.h new file +3 -0
+	struct list_head		attr_list;
+	struct attribute_group		attr_group;
+	const struct attribute_group	*groups[2];

Why 2? Docs should say at least.

include/linux/iio/counter.h line 147

Quoted 6 lines
include/linux/iio/counter.h new file +6 -0
+	size_t				num_attr;
+};
+
+/**
+ * struct counter_device_ext - Counter device extension
+ * @name:	[DRIVER] attribute name

Drop the [DRIVER] tag - it's not standard and doesn't add anything here!

Quoted 8 lines
include/linux/iio/counter.h new file +8 -0
+ * @read:	[DRIVER] read callback for this attribute; may be NULL
+ * @write:	[DRIVER] write callback for this attribute; may be NULL
+ * @priv:	[DRIVER] data private to the driver
+ */
+struct counter_device_ext {
+	const char	*name;
+	ssize_t		(*read)(struct counter_device *counter, void *priv,
+				char *buf);

include/linux/iio/counter.h line 165

Quoted 10 lines
include/linux/iio/counter.h new file +10 -0
+	ssize_t		(*write)(struct counter_device *counter, void *priv,
+				const char *buf, size_t len);
+	void		*priv;
+};
+
+/**
+ * struct counter_device - Counter data structure
+ * @name:		[DRIVER] name of the device
+ * @parent:		[DRIVER] optional parent device providing the counters
+ * @device_state:	[INTERN] internal device state container

Given I made up this convention (or stole it from somewhere) I feel justified in saying, don't use it here. Just mark the one item that is for internal use only.

Quoted 74 lines
include/linux/iio/counter.h new file +74 -0
+ * @signal_read:	[DRIVER] read callback for Signal attribute; may be NULL
+ * @signal_write:	[DRIVER] write callback for Signal attribute; may be
+ *			NULL
+ * @count_read:		[DRIVER] read callback for Count attribute; may be NULL
+ * @count_write:	[DRIVER] write callback for Count attribute; may be NULL
+ * @function_get:	[DRIVER] function to get the current count function
+ *			mode. Returns 0 on success and negative error code on
+ *			error. The index of the respective Count's returned
+ *			function mode should be passed back via the function
+ *			parameter.
+ * @function_set:	[DRIVER] function to set the count function mode.
+ *			function is the index of the requested function mode
+ *			from the respective Count's functions array.
+ * @action_get:		[DRIVER] function to get the current action mode.
+ *			Returns 0 on success and negative error code on error.
+ *			The index of the respective Signal's returned action
+ *			mode should be passed back via the action parameter.
+ * @action_set:		[DRIVER] function to set the action mode. action is the
+ *			index of the requested action mode from the respective
+ *			Synapse's actions array.
+ * @signals:		[DRIVER] array of Signals
+ * @num_signals:	[DRIVER] number of Signals specified in @signals
+ * @counts:		[DRIVER] array of Counts
+ * @num_counts:		[DRIVER] number of Counts specified in @counts
+ * @ext:		[DRIVER] optional array of Counter device extensions
+ * @num_ext:		[DRIVER] number of Counter device extensions specified
+ *			in @ext
+ * @priv:		[DRIVER] optional private data supplied by driver
+ */
+struct counter_device {
+	const char			*name;
+	struct device			*parent;
+	struct counter_device_state	*device_state;
+
+	ssize_t	(*signal_read)(struct counter_device *counter,
+			struct counter_signal *signal, char *buf);
+	ssize_t	(*signal_write)(struct counter_device *counter,
+			struct counter_signal *signal, const char *buf,
+			size_t len);
+	ssize_t	(*count_read)(struct counter_device *counter,
+			struct counter_count *count, char *buf);
+	ssize_t (*count_write)(struct counter_device *counter,
+			struct counter_count *count, const char *buf,
+			size_t len);
+	int	(*function_get)(struct counter_device *counter,
+			struct counter_count *count, size_t *function);
+	int	(*function_set)(struct counter_device *counter,
+			struct counter_count *count, size_t function);
+	int	(*action_get)(struct counter_device *counter,
+			struct counter_count *count,
+			struct counter_synapse *synapse, size_t *action);
+	int	(*action_set)(struct counter_device *counter,
+			struct counter_count *count,
+			struct counter_synapse *synapse, size_t action);
+
+	struct counter_signal	*signals;
+	size_t			num_signals;
+	struct counter_count	*counts;
+	size_t			num_counts;
+
+	const struct counter_device_ext	*ext;
+	size_t				num_ext;
+
+	void	*priv;
+};
+
+extern int counter_register(struct counter_device *const counter);
+extern void counter_unregister(struct counter_device *const counter);
+extern int devm_counter_register(struct device *dev,
+	struct counter_device *const counter);
+extern void devm_counter_unregister(struct device *dev,
+	struct counter_device *const counter);
+
+#endif /* _COUNTER_H_ */
#3 lore raw

PATCH v4 2/11 counter: Documentation: Add Generic Counter sysfs documentation

In reply to William Breathitt Gray

This patch adds standard documentation for the userspace sysfs attributes of the Generic Counter interface.

---
 .../ABI/testing/sysfs-bus-counter-generic-sysfs    | 73 ++++++++++++++++++++++
 MAINTAINERS                                        |  1 +
 2 files changed, 74 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs
Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs new file +73 -0
new file mode 100644
index 000000000000..3b1c3c4498d1
@@ -0,0 +1,73 @@
+What:		/sys/bus/counter/devices/counterX/countY
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Count data of Count Y. Typically, this is an accumulated count
+		value.
+
+What:		/sys/bus/counter/devices/counterX/countY_function
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Count function mode of Count Y; count function evaluation is
+		triggered by conditions specified by the countY_signalZ_action
+		attributes.
+
+What:		/sys/bus/counter/devices/counterX/countY_function_available
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Discrete set of available count function modes for the
+		configuration of the respective Count Y are listed in this file.
+
+What:		/sys/bus/counter/devices/counterX/countY_name
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Read-only attribute that indicates the device-specific name of
+		Count Y.
+
+What:		/sys/bus/counter/devices/counterX/countY_signalZ_action
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Action mode of Count Y for Signal Z. This attribute indicates
+		the condition of Signal Z that triggers the count function
+		evaluation for Count Y.
+
+What:		/sys/bus/counter/devices/counterX/countY_signalZ_action_available
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Discrete set of available action modes are listed in this file
+		for the configuration of the respective Synapse associating
+		Signal Z to Count Y.
+
+What:		/sys/bus/counter/devices/counterX/counter_name
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Read-only attribute that indicates the device-specific name of
+		the Counter.
+
+What:		/sys/bus/counter/devices/counterX/signalY
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Signal data of Signal Y. Typically, this is an input line level
+		state.
+
+What:		/sys/bus/counter/devices/counterX/signalY_name
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Read-only attribute that indicates the device-specific name of
+		Signal Y.
+
+What:		/sys/bus/counter/devices/counterX/countY_synapses
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		List of Synapses associating Signals to Count Y. The columns
+		represent the following in the respective order: Signal ID,
+		Signal name, and current action mode.
MAINTAINERS +1 -0
index 07dd7b933bfa..38da1bc615b3 100644
@@ -3665,6 +3665,7 @@ COUNTER INTERFACE
 M:	William Breathitt Gray <[email protected]>
 L:	[email protected]
 S:	Maintained
+F:	Documentation/ABI/testing/sysfs-bus-counter-*
 F:	drivers/iio/counter/
 F:	include/linux/iio/counter.h
 
Signature · 1 line
2.15.1
maintainer
#4 lore raw

Re: [PATCH v4 02/11] counter: Documentation: Add Generic Counter sysfs documentation

Quoted 20 lines · On Thu, 14 Dec 2017 15:50:58 -0500 William Breathitt Gray…

This patch adds standard documentation for the userspace sysfs attributes of the Generic Counter interface.

---
 .../ABI/testing/sysfs-bus-counter-generic-sysfs    | 73 ++++++++++++++++++++++
 MAINTAINERS                                        |  1 +
 2 files changed, 74 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs
Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs new file +4 -0
new file mode 100644
index 000000000000..3b1c3c4498d1
@@ -0,0 +1,73 @@
+What:		/sys/bus/counter/devices/counterX/countY
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:

Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs line 14

Quoted 10 lines
Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs new file +10 -0
+		Count data of Count Y. Typically, this is an accumulated count
+		value.
+
+What:		/sys/bus/counter/devices/counterX/countY_function
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Count function mode of Count Y; count function evaluation is
+		triggered by conditions specified by the countY_signalZ_action
+		attributes.

List possible values here or in the available. This document should fully define the interface.

Quoted 4 lines
Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs new file +4 -0
+
+What:		/sys/bus/counter/devices/counterX/countY_function_available
+KernelVersion:	4.16
+Contact:	[email protected]

Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs line 28

Quoted 10 lines
Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs new file +10 -0
+Description:
+		Discrete set of available count function modes for the
+		configuration of the respective Count Y are listed in this file.
+
+What:		/sys/bus/counter/devices/counterX/countY_name
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Read-only attribute that indicates the device-specific name of
+		Count Y.

It's specific to both the device and the count so make that clear. Also give a description of where it comes from. Who makes this up and how do they do it?

Quoted 6 lines
Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs new file +6 -0
+
+What:		/sys/bus/counter/devices/counterX/countY_signalZ_action
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Action mode of Count Y for Signal Z. This attribute indicates

Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs line 44

Quoted 10 lines
Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs new file +10 -0
+		the condition of Signal Z that triggers the count function
+		evaluation for Count Y.
+
+What:		/sys/bus/counter/devices/counterX/countY_signalZ_action_available
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Discrete set of available action modes are listed in this file
+		for the configuration of the respective Synapse associating
+		Signal Z to Count Y.

Again, all options need to be explicitly listed.

Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs line 51

Quoted 7 lines
Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs new file +7 -0
+
+What:		/sys/bus/counter/devices/counterX/counter_name
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Read-only attribute that indicates the device-specific name of
+		the Counter.

How is this decided? (actually the IIO docs are weak on this as well I think
- I should fix that as we frequently end up in a mess over this).

Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs line 58

Quoted 7 lines
Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs new file +7 -0
+
+What:		/sys/bus/counter/devices/counterX/signalY
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Signal data of Signal Y. Typically, this is an input line level
+		state.

I would avoid 'typically'. Just expand this text to cover new options when they occur.

Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs line 65

Quoted 7 lines
Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs new file +7 -0
+
+What:		/sys/bus/counter/devices/counterX/signalY_name
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Read-only attribute that indicates the device-specific name of
+		Signal Y.

Again, decided how?

Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs line 73

Quoted 8 lines
Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs new file +8 -0
+
+What:		/sys/bus/counter/devices/counterX/countY_synapses
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		List of Synapses associating Signals to Count Y. The columns
+		represent the following in the respective order: Signal ID,
+		Signal name, and current action mode.

This doesn't really conform to the sysfs golden rule of one attribute one thing.
An alternative I would look into would be to have countY_synapses directory containing a number of files to indicate this. Signal name looks redundant to me though as it can be established easily from the ID (I think). So I would have countY_synapses/synapse_signalX_action and the action in there.

Not totally sure how this would work out in reality but it would at least mean software only had to read the one it cared about rather than parse a table.

Quoted 12 lines
MAINTAINERS +1 -0
index 07dd7b933bfa..38da1bc615b3 100644
@@ -3665,6 +3665,7 @@ COUNTER INTERFACE
 M:	William Breathitt Gray <[email protected]>
 L:	[email protected]
 S:	Maintained
+F:	Documentation/ABI/testing/sysfs-bus-counter-*
 F:	drivers/iio/counter/
 F:	include/linux/iio/counter.h
 
#5 lore raw

PATCH v4 3/11 docs: Add Generic Counter interface documentation

In reply to William Breathitt Gray

This patch adds high-level documentation about the Generic Counter interface.

---
 Documentation/driver-api/iio/generic-counter.rst | 434 +++++++++++++++++++++++
 Documentation/driver-api/iio/index.rst           |   1 +
 MAINTAINERS                                      |   1 +
 3 files changed, 436 insertions(+)
 create mode 100644 Documentation/driver-api/iio/generic-counter.rst
Documentation/driver-api/iio/generic-counter.rst new file +434 -0
new file mode 100644
index 000000000000..219c571e90ce
@@ -0,0 +1,434 @@
+=========================
+Generic Counter Interface
+=========================
+
+Introduction
+============
+
+Counter devices are prevalent within a diverse spectrum of industries.
+The ubiquitous presence of these devices necessitates a common interface
+and standard of interaction and exposure. This driver API attempts to
+resolve the issue of duplicate code found among existing counter device
+drivers by introducing a generic counter interface for consumption. The
+Generic Counter interface enables drivers to support and expose a common
+set of components and functionality present in counter devices.
+
+Theory
+======
+
+Counter devices can vary greatly in design, but regardless of whether
+some devices are quadrature encoder counters or tally counters, all
+counter devices consist of a core set of components. This core set of
+components, shared by all counter devices, is what forms the essence of
+the Generic Counter interface.
+
+There are three core components to a counter:
+
+        COUNT
+        -----
+        A Count represents the count data for a set of Signals. A Count
+        has a count function mode (e.g. "increase" or "quadrature x4")
+        which represents the update behavior for the count data. A Count
+        also has a set of one or more associated Signals.
+
+        SIGNAL
+        ------
+        A Signal represents a counter input data; this is the data that
+        is typically analyzed by the counter to determine the count
+        data. A Signal may be associated to one or more Counts.
+
+        SYNAPSE
+        -------
+        A Synapse represents the association of a Signal with a
+        respective Count. Signal data affects respective Count data, and
+        the Synapse represents this relationship. The Synapse action
+        mode (e.g. "rising edge" or "double pulse") specifies the Signal
+        data condition which triggers the respective Count's count
+        function evaluation to update the count data. It is possible for
+        the Synapse action mode to be "none" if a Signal is associated
+        with a Count but does not trigger the count function (e.g. the
+        direction signal line for a Pulse-Direction encoding counter).
+
+A counter is defined as a set of input signals associated to count data
+that are generated by the evaluation of the state of the associated
+input signals as defined by the respective count functions. Within the
+context of the Generic Counter interface, a counter consists of Counts
+each associated to a set of Signals, whose respective Synapse instances
+represent the count function update conditions for the associated
+Counts.
+
+Paradigm
+========
+
+The most basic counter device may be expressed as a single Count
+associated with a single Signal via a single Synapse. Take for example
+a counter device which simply accumulates a count of rising edges on a
+source input line.
+
+        Count                Synapse        Signal
+        -----                -------        ------
++---------------------+
+| Data: Count         |    Rising Edge     ________
+| Function: Increase  |  <-------------   / Source \
+|                     |                  ____________
++---------------------+
+
+In this example, the Signal is a source input line with a pulsing
+voltage, while the Count is a persistent count value which is repeatedly
+incremented. The Signal is associated with the respective Count via a
+Synapse. The increase function is triggered by the Signal data condition
+specified by the Synapse -- in this case a rising edge condition on the
+voltage input line. In summary, the counter device existence and
+behavior is aptly represented by respective Count, Signal, and Synapse
+components: a rising edge condition triggers an increase function on an
+accumulating count datum.
+
+A counter device is not limited to a single Signal; in fact, in theory
+many number of Signals may be associated with even a single Count. For
+example, a quadrature encoder counter device can keep track of position
+based on the states of two input lines.
+
+           Count                 Synapse     Signal
+           -----                 -------     ------
++-------------------------+
+| Data: Position          |    Both Edges     ___
+| Function: Quadrature x4 |  <------------   / A \
+|                         |                 _______
+|                         |
+|                         |    Both Edges     ___
+|                         |  <------------   / B \
+|                         |                 _______
++-------------------------+
+
+In this example, two Signals (quadrature encoder lines A and B) are
+associated to a single Count: a rising or falling edge on either A or B
+triggers the "Quadrature x4" function which determines the direction of
+movement and updates the respective position data. The "Quadrature x4"
+function is likely implemented in the hardware of the quadrature encoder
+counter device; the Count, Signals, and Synapses simply represent this
+hardware behavior and functionality.
+
+Signals associated to the same Count can have differing Synapse action
+mode conditions. For example, a quadrature encoder counter device
+operating in a non-quadrature Pulse-Direction mode could have one input
+line dedicated for movement and a second input line dedicated for
+direction.
+
+           Count                   Synapse      Signal
+           -----                   -------      ------
++---------------------------+
+| Data: Position            |    Rising Edge     ___
+| Function: Pulse-Direction |  <-------------   / A \ (Movement)
+|                           |                  _______
+|                           |
+|                           |       None         ___
+|                           |  <-------------   / B \ (Direction)
+|                           |                  _______
++---------------------------+
+
+Only Signal A triggers the "Pulse-Direction" update function, but the
+instantaneous state of Signal B is still required in order to know the
+direction so that the position data may be properly updated. Ultimately,
+both Signals are associated to the same Count via two respective
+Synapses, but only one Synapse has an active action mode condition which
+triggers the respective count function while the other is left with a
+"None" condition action mode to indicate its respective Signal's
+availability for state evaluation despite its non-triggering mode.
+
+The flexibility of Synapses allows for the representation of counters
+whose respective Count Signal relationships would be difficult to
+represent as isolated inputs. For example a tri-color LED color counter
+can easily be represented with three Synapses:
+
+           Count          Synapse      Signal
+           -----          -------      ------
++------------------+
+| Data: Count      |    Both Edges     _______
+| Function: Purple |  <------------   /  Red  \
+|                  |                 ___________
+|                  |
+|                  |    Both Edges     _______
+|                  |  <------------   / Green \
+|                  |                 ___________
+|                  |
+|                  |    Both Edges     _______
+|                  |  <------------   / Blue  \
+|                  |                 ___________
++------------------+
+
+This counter accumulates the number of times the tri-color LED has
+turned to purple. By utilizing the Synapses to associate the three color
+Signals to the single Count, the count function evaluation relationship
+becomes apparent: combined color is checked when an individual color is
+turned on or off, and if only Red and Blue are active then Count datum
+is incremented to indicate the color has now turned to Purple.
+
+Although the examples thus far have been representations of physical
+devices, this is not a necessity. A counter simply represent the
+evaluation (Count) of input data (Signals) triggered by specific
+conditions (Synapses). A counter can be the representation of more
+abstract components.
+
+For example, suppose a counter representation is desired for a DNA
+sequence analysizer which detects possible genetic diseases.
+
+        Count                     Synapse            Signal
+        -----                     -------            ------
++---------------------+
+| Data: Diseases      |    Gene Transcript (EST)     _____
+| Function: Cancers   |  <-----------------------   / DNA \ (GAAGTGC...)
+|                     |                            _________
++---------------------+
+
+In this scenario, the Signal is a stream of DNA nucleotide bases (As,
+Ts, Cs, and Gs), the Synapse action modes consist of the various
+expressed sequence tags (ESTs), and the Count is a list of diseases
+discovered (in this particular example the function is evaluating for
+possible cancers). Note how the Signal in this example does not
+represent a physical voltage line, nor does the Synapse action mode
+represent a physical voltage line state change, nor does the Count
+represent a strictly decimal data value.
+
+The DNA sequence analysizer example is contrived to illustrate the
+flexibility of the generic counter paradigm by demonstrating its
+capability of representing abstract concepts; however, physical devices
+are likely to be more fitting for such a representation.
+
+The key concept is that the Signal, Synapse, and Count are abstract
+representations which do not need to be closely married to their
+respective physical sources. This allows the user of a counter to
+divorce themselves from the nuances of physical components (such as
+whether an input line is differential or single-ended) and focus on the
+core idea of what the data and process represent (e.g. an accumulated
+count of rising edges).
+
+Userspace Interface
+===================
+
+Several sysfs attributes are generated by the Generic Counter interface,
+and reside under the /sys/bus/counter/devices/counterX directory, where
+counterX refers to the respective counter device. Please see
+Documentation/ABI/testing/sys-bus-counter-generic-sysfs for detailed
+information on each Generic Counter interface sysfs attribute.
+
+Through these sysfs attributes, programs and scripts may interact with
+the Generic Counter paradigm Counts, Signals, and Synapses of respective
+counter devices.
+
+Driver API
+==========
+
+Driver authors may utilize the Generic Counter interface in their code
+by including the include/linux/iio/counter.h header file. This header
+file provides several core data structures and function prototypes for
+defining a generic counter.
+
+
+struct counter_signal_ext
+-------------------------
+
+This structure defines a Generic Counter Signal extension attribute.
+These attributes expose auxiliary configuration and functionality
+specific to the respective Generic Counter Signal.
+
+        name:   Attribute name
+        read:   Read callback for this attribute; may be NULL
+        write:  Write callback for this attribute; may be NULL
+        priv:   Data private to the driver
+
+struct counter_signal
+---------------------
+
+This structure defines a Generic Counter Signal component. Typically,
+this will correlate with an input channel on a physical counter device.
+This structure is the simplest of the Generic Counter paradigm core
+components to define with only two structure members which require
+explicit configuration:
+
+        id:             unique ID used to identify signal
+        name:           device-specific signal name
+        ext:            optional array of Counter Signal extensions
+        num_ext:        number of Counter Signal extensions specified in
+                        ext
+        priv:           optional private data supplied by driver
+
+struct counter_synapse
+----------------------
+
+This structure defines a Generic Counter Synapse component. To properly
+utilize this structure, action modes and an associated Signal must be
+defined:
+
+        action:         current action mode
+        actions:        available action modes
+        num_actions:    number of action modes specified in actions
+        signal:         pointer to associated signal
+
+struct counter_count_ext
+------------------------
+
+This structure defines a Generic Counter Count extension attribute.
+These attributes expose auxiliary configuration and functionality
+specific to the respective Generic Counter Count.
+
+        name:   attribute name
+        read:   read callback for this attribute; may be NULL
+        write:  write callback for this attribute; may be NULL
+        priv:   data private to the driver
+
+struct counter_count
+--------------------
+
+This structure defines a Generic Counter Count component. Typically,
+this will correlate with the read data (the "count" value) provided by a
+physical counter device. This structure requires the explicit
+configuration of an ID, name, function modes (the function triggered on
+a Synapse action condition), and a set of Synapses for the associated
+Signals:
+
+        id:             unique ID used to identify Count
+        name:           device-specific Count name
+        function:       current function mode
+        functions:      available function modes
+        num_functions:  number of functions specified in @functions
+        synapses:       array of synapses for initialization
+        num_synapses:   number of synapses specified in @synapses
+        ext:            optional array of Counter Count extensions
+        num_ext:        number of Counter Count extensions specified in
+                        ext
+        priv:           optional private data supplied by driver
+
+struct counter_device_ext
+-------------------------
+
+This structure defines a Generic Counter extension attribute. These
+attributes expose auxiliary configuration and functionality specific to
+the respective Generic Counter.
+
+        name:   attribute name
+        read:   read callback for this attribute; may be NULL
+        write:  write callback for this attribute; may be NULL
+        priv:   data private to the driver
+
+struct counter_device
+---------------------
+
+This is the main data structure for a Generic Counter device. Access to
+all respective Counts, Signals, and Synapses is possible from this
+structure. This structure requires the configuration of a name, Generic
+Counter Signals, and Generic Counter Counts:
+
+name:           name of the device
+parent:         optional parent device providing the counters
+signal_read:    read callback for Signal attribute; may be NULL
+signal_write:   write callback for Signal attribute; may be NULL
+count_read:     read callback for Count attribute; may be NULL
+count_write:    write callback for Count attribute; may be NULL
+function_get:   function to get the current count function mode. Returns
+                0 on success and negative error code on error. The index
+                of the respective Count's returned function mode should
+                be passed back via the function parameter.
+function_set:   function to set the count function mode. function is the
+                index of the requested function mode from the respective
+                Count's functions array.
+action_get:     function to get the current action mode. Returns 0 on
+                success and negative error code on error. The index of
+                the respective Signal's returned action mode should be
+                passed back via the action parameter.
+action_set:     function to set the action mode. action is the index of
+                the requested action mode from the respective Synapse's
+                actions array.
+signals:        array of Signals
+num_signals:    number of Signals specified in @signals
+counts:         array of Counts
+num_counts:     number of Counts specified in @counts
+ext:            optional array of Counter device extensions
+num_ext:        number of Counter device extensions specified in ext
+priv:           optional private data supplied by driver
+
+Registration functions
+----------------------
+
+A counter device is registered to the system by passing the respective
+initialized counter_device structure to the counter_register function;
+similarly, the counter_unregister function unregisters the respective
+Counter. The devm_counter_register and devm_counter_unregister functions
+serve as device memory-managed versions of the counter_register and
+counter_unregister functions respectively.
+
+Implementation
+==============
+
+To support a counter device, a driver must first allocate the available
+Counter Signals via counter_signal structures. These Signals should
+be stored as an array and set to the signals array member of an
+allocated counter_device structure before the Counter is registered to
+the system.
+
+Counter Counts may be allocated via counter_count structures, and
+respective Counter Signal associations (Synapses) made via
+counter_synapse structures. Associated counter_synapse structures are
+stored as an array and set to the the synapses array member of the
+respective counter_count structure. These counter_count structures are
+set to the counts array member of an allocated counter_device structure
+before the Counter is registered to the system.
+
+Driver callbacks should be provided to the counter_device structure in
+order to communicate with the device: to read and write various Signals
+and Counts, and to set and get the "action mode" and "function mode" for
+various Synapses and Counts respectively.
+
+A defined counter_device structure may be registered to the system by
+passing it to the counter_register function, and unregistered by passing
+it to the counter_unregister function. Similarly, the
+devm_counter_register and devm_counter_unregister functions may be used
+if device memory-managed registration is desired.
+
+Extension sysfs attributes can be created for auxiliary functionality
+and data by passing in defined counter_device_ext, counter_count_ext,
+and counter_signal_ext structures. In these cases, the
+counter_device_ext structure is used for global configuration of the
+respective Counter device, while the counter_count_ext and
+counter_signal_ext structures allow for auxiliary exposure and
+configuration of a specific Count or Signal respectively.
+
+Architecture
+============
+
+The counter_init function is called when the generic-counter module is
+loaded on the system. At this point, a bus_type named "counter" is
+registered and a dedicated "counter" chrdev region is allocated; these
+are removed and cleaned-up in the counter_exit function called when the
+generic-counter module is unloaded from the system.
+
+Counter devices are registered to the system via the counter_register
+function, and later removed via the counter_unregister function. The
+counter_register function establishes a unique ID for the Counter device
+and creates an associated device node under /dev called counterX, where
+X is the mentioned unique ID. A respective sysfs directory is created
+for the Counter device with a similar naming scheme:
+
+    /sys/bus/counter/devices/counterX
+
+Sysfs attributes are created within the counterX directory to expose
+functionality, configurations, and data relating to the Counts, Signals,
+and Synapses of the Counter device, as well as options and information
+for the Counter device itself.
+
+For a more detailed breakdown of the available Generic Counter interface
+sysfs attributes, please refer to the
+Documentation/ABI/testing/sys-bus-counter-generic-sysfs file.
+
+The Signals and Counts associated with the Counter device are registered
+to the system as well by the counter_register function. The
+signal_read/signal_write driver callbacks are associated to their
+respective Signal attributes, while the count_read/count_write and
+function_get/function_set driver callbacks are associated to their
+respective Count attributes; similarly, the same is true for the
+action_get/action_set driver callbacks and their respective Synapse
+attributes. If a driver callback is left undefined, then the respective
+read/write permission is left disabled for the relevant attributes.
+
+Similarly, extension sysfs attributes are created for the defined
+counter_device_ext, counter_count_ext, and counter_signal_ext
+structures that are passed in.
Documentation/driver-api/iio/index.rst +1 -0
index e5c3922d1b6f..e6c5b75c2e03 100644
@@ -15,3 +15,4 @@ Contents:
    buffers
    triggers
    triggered-buffers
+   generic-counter
MAINTAINERS +1 -0
index 38da1bc615b3..08eba78057e4 100644
@@ -3665,6 +3665,7 @@ COUNTER INTERFACE
 M:	William Breathitt Gray <[email protected]>
 L:	[email protected]
 S:	Maintained
+F:	Documentation/driver-api/counter/
 F:	Documentation/ABI/testing/sysfs-bus-counter-*
 F:	drivers/iio/counter/
 F:	include/linux/iio/counter.h
Signature · 1 line
2.15.1
maintainer
#6 lore raw

Re: [PATCH v4 03/11] docs: Add Generic Counter interface documentation

Quoted 45 lines · On Thu, 14 Dec 2017 15:51:16 -0500 William Breathitt Gray…

This patch adds high-level documentation about the Generic Counter interface.

---
 Documentation/driver-api/iio/generic-counter.rst | 434 +++++++++++++++++++++++
 Documentation/driver-api/iio/index.rst           |   1 +
 MAINTAINERS                                      |   1 +
 3 files changed, 436 insertions(+)
 create mode 100644 Documentation/driver-api/iio/generic-counter.rst
Documentation/driver-api/iio/generic-counter.rst new file +28 -0
new file mode 100644
index 000000000000..219c571e90ce
@@ -0,0 +1,434 @@
+=========================
+Generic Counter Interface
+=========================
+
+Introduction
+============
+
+Counter devices are prevalent within a diverse spectrum of industries.
+The ubiquitous presence of these devices necessitates a common interface
+and standard of interaction and exposure. This driver API attempts to
+resolve the issue of duplicate code found among existing counter device
+drivers by introducing a generic counter interface for consumption. The
+Generic Counter interface enables drivers to support and expose a common
+set of components and functionality present in counter devices.
+
+Theory
+======
+
+Counter devices can vary greatly in design, but regardless of whether
+some devices are quadrature encoder counters or tally counters, all
+counter devices consist of a core set of components. This core set of
+components, shared by all counter devices, is what forms the essence of
+the Generic Counter interface.
+
+There are three core components to a counter:
+
+        COUNT
+        -----

Documentation/driver-api/iio/generic-counter.rst line 38

Quoted 10 lines
Documentation/driver-api/iio/generic-counter.rst new file +10 -0
+        A Count represents the count data for a set of Signals. A Count
+        has a count function mode (e.g. "increase" or "quadrature x4")
+        which represents the update behavior for the count data. A Count
+        also has a set of one or more associated Signals.
+
+        SIGNAL
+        ------
+        A Signal represents a counter input data; this is the data that
+        is typically analyzed by the counter to determine the count
+        data. A Signal may be associated to one or more Counts.

I would give and example - input wire from a rotary encoder (perhaps)

Quoted 39 lines
Documentation/driver-api/iio/generic-counter.rst new file +39 -0
+
+        SYNAPSE
+        -------
+        A Synapse represents the association of a Signal with a
+        respective Count. Signal data affects respective Count data, and
+        the Synapse represents this relationship. The Synapse action
+        mode (e.g. "rising edge" or "double pulse") specifies the Signal
+        data condition which triggers the respective Count's count
+        function evaluation to update the count data. It is possible for
+        the Synapse action mode to be "none" if a Signal is associated
+        with a Count but does not trigger the count function (e.g. the
+        direction signal line for a Pulse-Direction encoding counter).
+
+A counter is defined as a set of input signals associated to count data
+that are generated by the evaluation of the state of the associated
+input signals as defined by the respective count functions. Within the
+context of the Generic Counter interface, a counter consists of Counts
+each associated to a set of Signals, whose respective Synapse instances
+represent the count function update conditions for the associated
+Counts.
+
+Paradigm
+========
+
+The most basic counter device may be expressed as a single Count
+associated with a single Signal via a single Synapse. Take for example
+a counter device which simply accumulates a count of rising edges on a
+source input line.
+
+        Count                Synapse        Signal
+        -----                -------        ------
++---------------------+
+| Data: Count         |    Rising Edge     ________
+| Function: Increase  |  <-------------   / Source \
+|                     |                  ____________
++---------------------+
+
+In this example, the Signal is a source input line with a pulsing
+voltage, while the Count is a persistent count value which is repeatedly

Documentation/driver-api/iio/generic-counter.rst line 87

Quoted 10 lines
Documentation/driver-api/iio/generic-counter.rst new file +10 -0
+incremented. The Signal is associated with the respective Count via a
+Synapse. The increase function is triggered by the Signal data condition
+specified by the Synapse -- in this case a rising edge condition on the
+voltage input line. In summary, the counter device existence and
+behavior is aptly represented by respective Count, Signal, and Synapse
+components: a rising edge condition triggers an increase function on an
+accumulating count datum.
+
+A counter device is not limited to a single Signal; in fact, in theory
+many number of Signals may be associated with even a single Count. For

many Signals

Quoted 4 lines
Documentation/driver-api/iio/generic-counter.rst new file +4 -0
+example, a quadrature encoder counter device can keep track of position
+based on the states of two input lines.
+
+           Count                 Synapse     Signal

Documentation/driver-api/iio/generic-counter.rst line 101

Quoted 10 lines
Documentation/driver-api/iio/generic-counter.rst new file +10 -0
+           -----                 -------     ------
++-------------------------+
+| Data: Position          |    Both Edges     ___
+| Function: Quadrature x4 |  <------------   / A \
+|                         |                 _______
+|                         |
+|                         |    Both Edges     ___
+|                         |  <------------   / B \
+|                         |                 _______
++-------------------------+

Perhaps add the external encoder itself to the asci art? Where are the signals coming from. It's not implausible down the line that you'll have to have explicit representation for that hardware. Could be a resolve to encoder convertor for example with its own control registers.

Quoted 53 lines
Documentation/driver-api/iio/generic-counter.rst new file +53 -0
+
+In this example, two Signals (quadrature encoder lines A and B) are
+associated to a single Count: a rising or falling edge on either A or B
+triggers the "Quadrature x4" function which determines the direction of
+movement and updates the respective position data. The "Quadrature x4"
+function is likely implemented in the hardware of the quadrature encoder
+counter device; the Count, Signals, and Synapses simply represent this
+hardware behavior and functionality.
+
+Signals associated to the same Count can have differing Synapse action
+mode conditions. For example, a quadrature encoder counter device
+operating in a non-quadrature Pulse-Direction mode could have one input
+line dedicated for movement and a second input line dedicated for
+direction.
+
+           Count                   Synapse      Signal
+           -----                   -------      ------
++---------------------------+
+| Data: Position            |    Rising Edge     ___
+| Function: Pulse-Direction |  <-------------   / A \ (Movement)
+|                           |                  _______
+|                           |
+|                           |       None         ___
+|                           |  <-------------   / B \ (Direction)
+|                           |                  _______
++---------------------------+
+
+Only Signal A triggers the "Pulse-Direction" update function, but the
+instantaneous state of Signal B is still required in order to know the
+direction so that the position data may be properly updated. Ultimately,
+both Signals are associated to the same Count via two respective
+Synapses, but only one Synapse has an active action mode condition which
+triggers the respective count function while the other is left with a
+"None" condition action mode to indicate its respective Signal's
+availability for state evaluation despite its non-triggering mode.
+
+The flexibility of Synapses allows for the representation of counters
+whose respective Count Signal relationships would be difficult to
+represent as isolated inputs. For example a tri-color LED color counter
+can easily be represented with three Synapses:
+
+           Count          Synapse      Signal
+           -----          -------      ------
++------------------+
+| Data: Count      |    Both Edges     _______
+| Function: Purple |  <------------   /  Red  \
+|                  |                 ___________
+|                  |
+|                  |    Both Edges     _______
+|                  |  <------------   / Green \
+|                  |                 ___________
+|                  |
+|                  |    Both Edges     _______

Documentation/driver-api/iio/generic-counter.rst line 164

Quoted 10 lines
Documentation/driver-api/iio/generic-counter.rst new file +10 -0
+|                  |  <------------   / Blue  \
+|                  |                 ___________
++------------------+
+
+This counter accumulates the number of times the tri-color LED has
+turned to purple. By utilizing the Synapses to associate the three color
+Signals to the single Count, the count function evaluation relationship
+becomes apparent: combined color is checked when an individual color is
+turned on or off, and if only Red and Blue are active then Count datum
+is incremented to indicate the color has now turned to Purple.

This one has somewhat drifted away from common cases. I'm not sure it is necessary to understanding so I'd be tempted to drop it as the only potential this and the one below have right now is to distract from the code we are actually interested in getting reviewed.

Quoted 38 lines
Documentation/driver-api/iio/generic-counter.rst new file +38 -0
+
+Although the examples thus far have been representations of physical
+devices, this is not a necessity. A counter simply represent the
+evaluation (Count) of input data (Signals) triggered by specific
+conditions (Synapses). A counter can be the representation of more
+abstract components.
+
+For example, suppose a counter representation is desired for a DNA
+sequence analysizer which detects possible genetic diseases.
+
+        Count                     Synapse            Signal
+        -----                     -------            ------
++---------------------+
+| Data: Diseases      |    Gene Transcript (EST)     _____
+| Function: Cancers   |  <-----------------------   / DNA \ (GAAGTGC...)
+|                     |                            _________
++---------------------+
+
+In this scenario, the Signal is a stream of DNA nucleotide bases (As,
+Ts, Cs, and Gs), the Synapse action modes consist of the various
+expressed sequence tags (ESTs), and the Count is a list of diseases
+discovered (in this particular example the function is evaluating for
+possible cancers). Note how the Signal in this example does not
+represent a physical voltage line, nor does the Synapse action mode
+represent a physical voltage line state change, nor does the Count
+represent a strictly decimal data value.
+
+The DNA sequence analysizer example is contrived to illustrate the
+flexibility of the generic counter paradigm by demonstrating its
+capability of representing abstract concepts; however, physical devices
+are likely to be more fitting for such a representation.
+
+The key concept is that the Signal, Synapse, and Count are abstract
+representations which do not need to be closely married to their
+respective physical sources. This allows the user of a counter to
+divorce themselves from the nuances of physical components (such as
+whether an input line is differential or single-ended) and focus on the
+core idea of what the data and process represent (e.g. an accumulated

Documentation/driver-api/iio/generic-counter.rst line 212

Quoted 10 lines
Documentation/driver-api/iio/generic-counter.rst new file +10 -0
+count of rising edges).
+
+Userspace Interface
+===================
+
+Several sysfs attributes are generated by the Generic Counter interface,
+and reside under the /sys/bus/counter/devices/counterX directory, where
+counterX refers to the respective counter device. Please see
+Documentation/ABI/testing/sys-bus-counter-generic-sysfs for detailed
+information on each Generic Counter interface sysfs attribute.

I would loose the generic-sysfs off that filename. sys-bus-counter itself means it covers the generic stuff.

Quoted 27 lines
Documentation/driver-api/iio/generic-counter.rst new file +27 -0
+
+Through these sysfs attributes, programs and scripts may interact with
+the Generic Counter paradigm Counts, Signals, and Synapses of respective
+counter devices.
+
+Driver API
+==========
+
+Driver authors may utilize the Generic Counter interface in their code
+by including the include/linux/iio/counter.h header file. This header
+file provides several core data structures and function prototypes for
+defining a generic counter.
+
+
+struct counter_signal_ext
+-------------------------
+
+This structure defines a Generic Counter Signal extension attribute.
+These attributes expose auxiliary configuration and functionality
+specific to the respective Generic Counter Signal.
+
+        name:   Attribute name
+        read:   Read callback for this attribute; may be NULL
+        write:  Write callback for this attribute; may be NULL
+        priv:   Data private to the driver
+
+struct counter_signal

Documentation/driver-api/iio/generic-counter.rst line 249

Quoted 10 lines
Documentation/driver-api/iio/generic-counter.rst new file +10 -0
+---------------------
+
+This structure defines a Generic Counter Signal component. Typically,
+this will correlate with an input channel on a physical counter device.
+This structure is the simplest of the Generic Counter paradigm core
+components to define with only two structure members which require
+explicit configuration:
+
+        id:             unique ID used to identify signal
+        name:           device-specific signal name

Again, guidance needed on what this actually should be. It's an important bit of the ABI so best to document what the form of these things should be.

Quoted 4 lines
Documentation/driver-api/iio/generic-counter.rst new file +4 -0
+        ext:            optional array of Counter Signal extensions
+        num_ext:        number of Counter Signal extensions specified in
+                        ext
+        priv:           optional private data supplied by driver

Documentation/driver-api/iio/generic-counter.rst line 263

Quoted 10 lines
Documentation/driver-api/iio/generic-counter.rst new file +10 -0
+
+struct counter_synapse
+----------------------
+
+This structure defines a Generic Counter Synapse component. To properly
+utilize this structure, action modes and an associated Signal must be
+defined:
+
+        action:         current action mode
+        actions:        available action modes

I would make the names more distinct as action vs actions will not be easy to read in the code.

Quoted 18 lines
Documentation/driver-api/iio/generic-counter.rst new file +18 -0
+        num_actions:    number of action modes specified in actions
+        signal:         pointer to associated signal
+
+struct counter_count_ext
+------------------------
+
+This structure defines a Generic Counter Count extension attribute.
+These attributes expose auxiliary configuration and functionality
+specific to the respective Generic Counter Count.
+
+        name:   attribute name
+        read:   read callback for this attribute; may be NULL
+        write:  write callback for this attribute; may be NULL
+        priv:   data private to the driver
+
+struct counter_count
+--------------------
+

Documentation/driver-api/iio/generic-counter.rst line 291

Quoted 10 lines
Documentation/driver-api/iio/generic-counter.rst new file +10 -0
+This structure defines a Generic Counter Count component. Typically,
+this will correlate with the read data (the "count" value) provided by a
+physical counter device. This structure requires the explicit
+configuration of an ID, name, function modes (the function triggered on
+a Synapse action condition), and a set of Synapses for the associated
+Signals:
+
+        id:             unique ID used to identify Count
+        name:           device-specific Count name
+        function:       current function mode

current_function or similar will make it more distinct from just the plural.

Quoted 101 lines
Documentation/driver-api/iio/generic-counter.rst new file +101 -0
+        functions:      available function modes
+        num_functions:  number of functions specified in @functions
+        synapses:       array of synapses for initialization
+        num_synapses:   number of synapses specified in @synapses
+        ext:            optional array of Counter Count extensions
+        num_ext:        number of Counter Count extensions specified in
+                        ext
+        priv:           optional private data supplied by driver
+
+struct counter_device_ext
+-------------------------
+
+This structure defines a Generic Counter extension attribute. These
+attributes expose auxiliary configuration and functionality specific to
+the respective Generic Counter.
+
+        name:   attribute name
+        read:   read callback for this attribute; may be NULL
+        write:  write callback for this attribute; may be NULL
+        priv:   data private to the driver
+
+struct counter_device
+---------------------
+
+This is the main data structure for a Generic Counter device. Access to
+all respective Counts, Signals, and Synapses is possible from this
+structure. This structure requires the configuration of a name, Generic
+Counter Signals, and Generic Counter Counts:
+
+name:           name of the device
+parent:         optional parent device providing the counters
+signal_read:    read callback for Signal attribute; may be NULL
+signal_write:   write callback for Signal attribute; may be NULL
+count_read:     read callback for Count attribute; may be NULL
+count_write:    write callback for Count attribute; may be NULL
+function_get:   function to get the current count function mode. Returns
+                0 on success and negative error code on error. The index
+                of the respective Count's returned function mode should
+                be passed back via the function parameter.
+function_set:   function to set the count function mode. function is the
+                index of the requested function mode from the respective
+                Count's functions array.
+action_get:     function to get the current action mode. Returns 0 on
+                success and negative error code on error. The index of
+                the respective Signal's returned action mode should be
+                passed back via the action parameter.
+action_set:     function to set the action mode. action is the index of
+                the requested action mode from the respective Synapse's
+                actions array.
+signals:        array of Signals
+num_signals:    number of Signals specified in @signals
+counts:         array of Counts
+num_counts:     number of Counts specified in @counts
+ext:            optional array of Counter device extensions
+num_ext:        number of Counter device extensions specified in ext
+priv:           optional private data supplied by driver
+
+Registration functions
+----------------------
+
+A counter device is registered to the system by passing the respective
+initialized counter_device structure to the counter_register function;
+similarly, the counter_unregister function unregisters the respective
+Counter. The devm_counter_register and devm_counter_unregister functions
+serve as device memory-managed versions of the counter_register and
+counter_unregister functions respectively.
+
+Implementation
+==============
+
+To support a counter device, a driver must first allocate the available
+Counter Signals via counter_signal structures. These Signals should
+be stored as an array and set to the signals array member of an
+allocated counter_device structure before the Counter is registered to
+the system.
+
+Counter Counts may be allocated via counter_count structures, and
+respective Counter Signal associations (Synapses) made via
+counter_synapse structures. Associated counter_synapse structures are
+stored as an array and set to the the synapses array member of the
+respective counter_count structure. These counter_count structures are
+set to the counts array member of an allocated counter_device structure
+before the Counter is registered to the system.
+
+Driver callbacks should be provided to the counter_device structure in
+order to communicate with the device: to read and write various Signals
+and Counts, and to set and get the "action mode" and "function mode" for
+various Synapses and Counts respectively.
+
+A defined counter_device structure may be registered to the system by
+passing it to the counter_register function, and unregistered by passing
+it to the counter_unregister function. Similarly, the
+devm_counter_register and devm_counter_unregister functions may be used
+if device memory-managed registration is desired.
+
+Extension sysfs attributes can be created for auxiliary functionality
+and data by passing in defined counter_device_ext, counter_count_ext,
+and counter_signal_ext structures. In these cases, the
+counter_device_ext structure is used for global configuration of the
+respective Counter device, while the counter_count_ext and
+counter_signal_ext structures allow for auxiliary exposure and

Documentation/driver-api/iio/generic-counter.rst line 402

Quoted 10 lines
Documentation/driver-api/iio/generic-counter.rst new file +10 -0
+configuration of a specific Count or Signal respectively.
+
+Architecture
+============
+
+The counter_init function is called when the generic-counter module is
+loaded on the system. At this point, a bus_type named "counter" is
+registered and a dedicated "counter" chrdev region is allocated; these
+are removed and cleaned-up in the counter_exit function called when the
+generic-counter module is unloaded from the system.

What's the chrdev for?

Quoted 37 lines
Documentation/driver-api/iio/generic-counter.rst new file +32 -0
+
+Counter devices are registered to the system via the counter_register
+function, and later removed via the counter_unregister function. The
+counter_register function establishes a unique ID for the Counter device
+and creates an associated device node under /dev called counterX, where
+X is the mentioned unique ID. A respective sysfs directory is created
+for the Counter device with a similar naming scheme:
+
+    /sys/bus/counter/devices/counterX
+
+Sysfs attributes are created within the counterX directory to expose
+functionality, configurations, and data relating to the Counts, Signals,
+and Synapses of the Counter device, as well as options and information
+for the Counter device itself.
+
+For a more detailed breakdown of the available Generic Counter interface
+sysfs attributes, please refer to the
+Documentation/ABI/testing/sys-bus-counter-generic-sysfs file.
+
+The Signals and Counts associated with the Counter device are registered
+to the system as well by the counter_register function. The
+signal_read/signal_write driver callbacks are associated to their
+respective Signal attributes, while the count_read/count_write and
+function_get/function_set driver callbacks are associated to their
+respective Count attributes; similarly, the same is true for the
+action_get/action_set driver callbacks and their respective Synapse
+attributes. If a driver callback is left undefined, then the respective
+read/write permission is left disabled for the relevant attributes.
+
+Similarly, extension sysfs attributes are created for the defined
+counter_device_ext, counter_count_ext, and counter_signal_ext
+structures that are passed in.
Documentation/driver-api/iio/index.rst +0 -0
index e5c3922d1b6f..e6c5b75c2e03 100644

Documentation/driver-api/iio/index.rst Contents: · line 18

Quoted 4 lines
Documentation/driver-api/iio/index.rst +1 -0
@@ -15,3 +15,4 @@ Contents:
    buffers
    triggers
    triggered-buffers
+   generic-counter

I would give it a category to itself and not put it under the iio docs (unless you decide to host in IIO)

Quoted 12 lines
MAINTAINERS +1 -0
index 38da1bc615b3..08eba78057e4 100644
@@ -3665,6 +3665,7 @@ COUNTER INTERFACE
 M:	William Breathitt Gray <[email protected]>
 L:	[email protected]
 S:	Maintained
+F:	Documentation/driver-api/counter/
 F:	Documentation/ABI/testing/sysfs-bus-counter-*
 F:	drivers/iio/counter/
 F:	include/linux/iio/counter.h
#7 lore raw

PATCH v4 4/11 counter: Introduce the Simple Counter interface

In reply to William Breathitt Gray

This patch introduces the Simple Counter interface. The Simple Counter interface serves as an API to provide support for simple hardware counter devices. The Simple Counter interface is built on top of the Generic Counter interface.

A simple hardware counter device is a counter device that has a single signal associated with each count value; Signals may have a value of "low" or "high," and edge trigger the count function which either increases or decreases the respective count value.

The Simple Counter interface provides two count function modes:

SIMPLE_COUNTER_FUNCTION_INCREASE: "increase" SIMPLE_COUNTER_FUNCTION_DECREASE: "decrease"

The Simple Counter interface provides four action modes:

SIMPLE_COUNTER_ACTION_NONE: "none" SIMPLE_COUNTER_ACTION_RISING_EDGE: "rising edge" SIMPLE_COUNTER_ACTION_FALLING_EDGE: "falling edge" SIMPLE_COUNTER_ACTION_BOTH_EDGES: "both edges"

Signals may be represented by two possible states:

SIMPLE_COUNTER_SIGNAL_LOW: "low"
SIMPLE_COUNTER_SIGNAL_HIGH: "high"

Since the Simple Counter interface utilizes the Generic Counter interface underneath, all the expected functionality of the Generic Counter interface such as sysfs attributes is exposed to userspace for end user consumption. The Simple Counter interface serves as a convenience API for supporting a common class of counter devices without the need to manually configure the more cumbersome Generic Counter interface for use.

To use the Simple Counter interface, create an array of simple_counter_count structures to represent the desired counts and signals of the counter device, allocate a simple_counter_device structure and populate it with respective driver callbacks and the simple_counter_count array created earlier, then register the counter by calling the simple_counter_register function. The simple_counter_unregister function may be used to unregistered a previously registered counter.

Memory-managed versions of simple_counter_register and simple_counter_unregister functions are provided by the devm_simple_counter_register and devm_simple_counter_unregister functions respectively.

---
 drivers/iio/counter/Kconfig          |   4 +-
 drivers/iio/counter/Makefile         |   1 +
 drivers/iio/counter/simple-counter.c | 734 +++++++++++++++++++++++++++++++++++
 include/linux/iio/counter.h          | 199 ++++++++++
 4 files changed, 937 insertions(+), 1 deletion(-)
 create mode 100644 drivers/iio/counter/simple-counter.c
drivers/iio/counter/Kconfig +3 -1
index 4eaf4e53c5aa..6b9a43180d2c 100644
@@ -8,7 +8,9 @@ menuconfig COUNTER
 	help
 	  Provides support for Counter devices. The Generic Counter API provides
 	  rudimentary support for counters and serves as building blocks to
-	  create more complex counter interfaces.
+	  create more complex counter interfaces. The Simple Counter API
+	  provides support for simple hardware counter devices that have a
+	  one-to-one mapping between their Signals and Counts.
 
 if COUNTER
 
drivers/iio/counter/Makefile +1 -0
index 513c49d832d4..7450dee97446 100644
@@ -6,6 +6,7 @@
 
 obj-$(CONFIG_COUNTER) += counter.o
 counter-$(CONFIG_COUNTER) += generic-counter.o
+counter-$(CONFIG_COUNTER) += simple-counter.o
 
 obj-$(CONFIG_104_QUAD_8)	+= 104-quad-8.o
 obj-$(CONFIG_STM32_LPTIMER_CNT)	+= stm32-lptimer-cnt.o
drivers/iio/counter/simple-counter.c new file +734 -0

734 lines not on this page · raw message

include/linux/iio/counter.h +199 -0

203 lines not on this page · raw message

Signature · 1 line
2.15.1
maintainer
#8 lore raw

Re: [PATCH v4 04/11] counter: Introduce the Simple Counter interface

Quoted 10 lines · On Thu, 14 Dec 2017 15:51:30 -0500 William Breathitt Gray…

This patch introduces the Simple Counter interface. The Simple Counter interface serves as an API to provide support for simple hardware counter devices. The Simple Counter interface is built on top of the Generic Counter interface.

A simple hardware counter device is a counter device that has a single signal associated with each count value; Signals may have a value of "low" or "high," and edge trigger the count function which either increases or decreases the respective count value.

Quoted 8 lines

The Simple Counter interface provides two count function modes:

SIMPLE_COUNTER_FUNCTION_INCREASE: "increase" SIMPLE_COUNTER_FUNCTION_DECREASE: "decrease"

The Simple Counter interface provides four action modes:

SIMPLE_COUNTER_ACTION_NONE: "none"

How does this one make sense for a simple counter? Presumably really just means "off"

Quoted 26 lines

SIMPLE_COUNTER_ACTION_RISING_EDGE: "rising edge" SIMPLE_COUNTER_ACTION_FALLING_EDGE: "falling edge" SIMPLE_COUNTER_ACTION_BOTH_EDGES: "both edges"

Signals may be represented by two possible states:

SIMPLE_COUNTER_SIGNAL_LOW: "low"
SIMPLE_COUNTER_SIGNAL_HIGH: "high"

Since the Simple Counter interface utilizes the Generic Counter interface underneath, all the expected functionality of the Generic Counter interface such as sysfs attributes is exposed to userspace for end user consumption. The Simple Counter interface serves as a convenience API for supporting a common class of counter devices without the need to manually configure the more cumbersome Generic Counter interface for use.

To use the Simple Counter interface, create an array of simple_counter_count structures to represent the desired counts and signals of the counter device, allocate a simple_counter_device structure and populate it with respective driver callbacks and the simple_counter_count array created earlier, then register the counter by calling the simple_counter_register function. The simple_counter_unregister function may be used to unregistered a previously registered counter.

Quoted 4 lines

Memory-managed versions of simple_counter_register and simple_counter_unregister functions are provided by the devm_simple_counter_register and devm_simple_counter_unregister functions respectively.

A few little items inline.

My main concern here is it's a lot of code for a relatively small amount of functionality. I can't immediately see how to make a large difference on that though.

Quoted 625 lines
---
 drivers/iio/counter/Kconfig          |   4 +-
 drivers/iio/counter/Makefile         |   1 +
 drivers/iio/counter/simple-counter.c | 734 +++++++++++++++++++++++++++++++++++
 include/linux/iio/counter.h          | 199 ++++++++++
 4 files changed, 937 insertions(+), 1 deletion(-)
 create mode 100644 drivers/iio/counter/simple-counter.c
drivers/iio/counter/Kconfig +3 -1
index 4eaf4e53c5aa..6b9a43180d2c 100644
@@ -8,7 +8,9 @@ menuconfig COUNTER
 	help
 	  Provides support for Counter devices. The Generic Counter API provides
 	  rudimentary support for counters and serves as building blocks to
-	  create more complex counter interfaces.
+	  create more complex counter interfaces. The Simple Counter API
+	  provides support for simple hardware counter devices that have a
+	  one-to-one mapping between their Signals and Counts.
 
 if COUNTER
 
drivers/iio/counter/Makefile +1 -0
index 513c49d832d4..7450dee97446 100644
@@ -6,6 +6,7 @@
 
 obj-$(CONFIG_COUNTER) += counter.o
 counter-$(CONFIG_COUNTER) += generic-counter.o
+counter-$(CONFIG_COUNTER) += simple-counter.o
 
 obj-$(CONFIG_104_QUAD_8)	+= 104-quad-8.o
 obj-$(CONFIG_STM32_LPTIMER_CNT)	+= stm32-lptimer-cnt.o
drivers/iio/counter/simple-counter.c new file +582 -0
new file mode 100644
index 000000000000..e061db0860fd
@@ -0,0 +1,734 @@
+/*
+ * Simple Counter interface
+ * Copyright (C) 2017 William Breathitt Gray
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <linux/iio/counter.h>
+
+static const char *const simple_counter_signal_level_names[] = {
+	[SIMPLE_COUNTER_SIGNAL_LOW] = "low",
+	[SIMPLE_COUNTER_SIGNAL_HIGH] = "high"
+};
+
+static ssize_t simple_counter_signal_read(struct counter_device *counter_dev,
+	struct counter_signal *counter_sig, char *buf)
+{
+	struct simple_counter_device *const counter = counter_dev->priv;
+	struct simple_counter_signal *const signal = counter_sig->priv;
+	int err;
+	enum simple_counter_signal_level level;
+
+	err = counter->signal_read(counter, signal, &level);
+	if (err)
+		return err;
+
+	return scnprintf(buf, PAGE_SIZE, "%s\n",
+		simple_counter_signal_level_names[level]);
+}
+
+static ssize_t simple_counter_signal_write(struct counter_device *counter_dev,
+	struct counter_signal *counter_sig, const char *buf, size_t len)
+{
+	struct simple_counter_device *const counter = counter_dev->priv;
+	struct simple_counter_signal *const signal = counter_sig->priv;
+	int level;
+	int err;
+
+	level = sysfs_match_string(simple_counter_signal_level_names, buf);
+	if (level < 0)
+		return level;
+
+	err = counter->signal_write(counter, signal, level);
+	if (err)
+		return err;
+
+	return len;
+}
+
+static ssize_t simple_counter_count_read(struct counter_device *counter_dev,
+	struct counter_count *counter_cnt, char *buf)
+{
+	struct simple_counter_device *const counter = counter_dev->priv;
+	struct simple_counter_count *const count = counter_cnt->priv;
+	int err;
+	long val;
+
+	err = counter->count_read(counter, count, &val);
+	if (err)
+		return err;
+
+	return scnprintf(buf, PAGE_SIZE, "%ld\n", val);
+}
+
+static ssize_t simple_counter_count_write(struct counter_device *counter_dev,
+	struct counter_count *counter_cnt, const char *buf, size_t len)
+{
+	struct simple_counter_device *const counter = counter_dev->priv;
+	struct simple_counter_count *const count = counter_cnt->priv;
+	int err;
+	long val;
+
+	err = kstrtol(buf, 0, &val);
+	if (err)
+		return err;
+
+	err = counter->count_write(counter, count, val);
+	if (err)
+		return err;
+
+	return len;
+}
+
+static int simple_counter_function_get(struct counter_device *counter_dev,
+	struct counter_count *counter_cnt, size_t *counter_func)
+{
+	int err;
+	struct simple_counter_device *const counter = counter_dev->priv;
+	struct simple_counter_count *const count = counter_cnt->priv;
+	enum simple_counter_function function;
+
+	err = counter->function_get(counter, count, &function);
+	if (err)
+		return err;
+
+	count->function = function;
+
+	*counter_func = function;
+
+	return 0;
+}
+
+static int simple_counter_function_set(struct counter_device *counter_dev,
+	struct counter_count *counter_cnt, size_t function)
+{
+	struct simple_counter_device *const counter = counter_dev->priv;
+	struct simple_counter_count *const count = counter_cnt->priv;
+	int err;
+
+	err = counter->function_set(counter, count, function);
+	if (err)
+		return err;
+
+	count->function = function;
+
+	return 0;
+}
+
+static int simple_counter_action_get(struct counter_device *counter_dev,
+	struct counter_count *counter_cnt, struct counter_synapse *counter_syn,
+	size_t *counter_act)
+{
+	int err;
+	struct simple_counter_device *const counter = counter_dev->priv;
+	struct simple_counter_count *const count = counter_cnt->priv;
+	enum simple_counter_action action;
+
+	err = counter->action_get(counter, count, &action);
+	if (err)
+		return err;
+
+	count->action = action;
+
+	*counter_act = action;
+
+	return 0;
+}
+
+static int simple_counter_action_set(struct counter_device *counter_dev,
+	struct counter_count *counter_cnt, struct counter_synapse *counter_syn,
+	size_t action)
+{
+	struct simple_counter_device *const counter = counter_dev->priv;
+	struct simple_counter_count *const count = counter_cnt->priv;
+	int err;
+
+	err = counter->action_set(counter, count, action);
+	if (err)
+		return err;
+
+	count->action = action;
+
+	return 0;
+}
+
+static ssize_t simple_counter_signal_ext_read(struct counter_device *dev,
+	struct counter_signal *signal, void *priv, char *buf)
+{
+	const struct simple_counter_signal_ext *const ext = priv;
+	struct simple_counter_device *const counter = dev->priv;
+	struct simple_counter_signal *const simple_signal = signal->priv;
+
+	return ext->read(counter, simple_signal, ext->priv, buf);
+}
+
+static ssize_t simple_counter_signal_ext_write(struct counter_device *dev,
+	struct counter_signal *signal, void *priv, const char *buf, size_t len)
+{
+	const struct simple_counter_signal_ext *const ext = priv;
+	struct simple_counter_device *const counter = dev->priv;
+	struct simple_counter_signal *const simple_signal = signal->priv;
+
+	return ext->write(counter, simple_signal, ext->priv, buf, len);
+}
+
+static int simple_counter_counter_signal_ext_register(
+	const struct simple_counter_signal *const simple_signal,
+	struct counter_signal *const signal)
+{
+	const struct simple_counter_signal_ext *const simple_ext =
+		simple_signal->ext;
+	const size_t num_ext = simple_signal->num_ext;
+	struct counter_signal_ext *ext;
+	size_t i;
+
+	/* Return early if no extensions */
+	if (!simple_ext || !num_ext)
+		return 0;
+
+	/* Allocate space for counter_signal_ext array */
+	ext = kmalloc_array(num_ext, sizeof(*ext), GFP_KERNEL);
+	if (!ext)
+		return -ENOMEM;
+
+	/* Register simple_counter_signal_ext via counter_signal_ext */
+	for (i = 0; i < num_ext; i++) {
+		ext[i].name = simple_ext[i].name;
+		ext[i].read = (simple_ext[i].read) ?
+			simple_counter_signal_ext_read : NULL;
+		ext[i].write = (simple_ext[i].write) ?
+			simple_counter_signal_ext_write : NULL;
+		ext[i].priv = simple_ext + i;
+	}
+
+	/* Register Counter Signal extensions */
+	signal->ext = ext;
+	signal->num_ext = num_ext;
+
+	return 0;
+}
+
+static int simple_counter_counter_signals_register(
+	const struct simple_counter_device *const counter)
+{
+	const size_t num_counts = counter->num_counts;
+	struct counter_signal *signals;
+	const size_t num_signals = num_counts;
+	struct simple_counter_count *const simple_counts = counter->counts;
+	size_t i;
+	struct counter_signal *signal;
+	struct simple_counter_signal *simple_signal;
+	int err;
+	struct counter_device *const counter_dev = counter->counter_dev;
+
+	/* Allocate space for signals array */
+	signals = kcalloc(num_signals, sizeof(*signals), GFP_KERNEL);
+	if (!signals)
+		return -ENOMEM;
+
+	/* Configure Signals */
+	for (i = 0; i < num_signals; i++) {
+		signal = signals + i;
+		simple_signal = &simple_counts[i].signal;
+
+		signal->id = simple_signal->id;
+		signal->name = simple_signal->name;
+		signal->priv = simple_signal;
+
+		/* Register Counter Signal extensions */
+		err = simple_counter_counter_signal_ext_register(simple_signal,
+			signal);
+		if (err)
+			goto err_free_signals;
+	}
+
+	/* Register Signals to Counter device container */
+	counter_dev->signals = signals;
+	counter_dev->num_signals = num_signals;
+
+	return 0;
+
+err_free_signals:
+	while (i--)
+		kfree(signals[i].ext);
+	kfree(signals);
+	return err;
+}
+
+static const char *const simple_counter_function_names[] = {
+	[SIMPLE_COUNTER_FUNCTION_INCREASE] = "increase",
+	[SIMPLE_COUNTER_FUNCTION_DECREASE] = "decrease"
+};
+
+static const char *const simple_counter_action_names[] = {
+	[SIMPLE_COUNTER_ACTION_NONE] = "none",
+	[SIMPLE_COUNTER_ACTION_RISING_EDGE] = "rising edge",
+	[SIMPLE_COUNTER_ACTION_FALLING_EDGE] = "falling edge",
+	[SIMPLE_COUNTER_ACTION_BOTH_EDGES] = "both edges"
+};
+
+static int simple_counter_counter_synapse_register(
+	struct counter_signal *const signal, struct counter_count *const count)
+{
+	struct counter_synapse *synapse;
+
+	/* Allocate space for Counter Synapse */
+	synapse = kzalloc(sizeof(*synapse), GFP_KERNEL);
+	if (!synapse)
+		return -ENOMEM;
+
+	/* Configure Synapse */
+	synapse->signal = signal;
+	synapse->actions = simple_counter_action_names;
+	synapse->num_actions = ARRAY_SIZE(simple_counter_action_names);
+
+	/* Register Counter Synapse */
+	count->synapses = synapse;
+	count->num_synapses = 1;
+
+	return 0;
+}
+
+static ssize_t simple_counter_count_ext_read(struct counter_device *dev,
+	struct counter_count *count, void *priv, char *buf)
+{
+	const struct simple_counter_count_ext *const ext = priv;
+	struct simple_counter_device *const counter = dev->priv;
+	struct simple_counter_count *const simple_count = count->priv;
+
+	return ext->read(counter, simple_count, ext->priv, buf);
+}
+
+static ssize_t simple_counter_count_ext_write(struct counter_device *dev,
+	struct counter_count *count, void *priv, const char *buf, size_t len)
+{
+	const struct simple_counter_count_ext *const ext = priv;
+	struct simple_counter_device *const counter = dev->priv;
+	struct simple_counter_count *const simple_count = count->priv;
+
+	return ext->write(counter, simple_count, ext->priv, buf, len);
+}
+
+static int simple_counter_counter_count_ext_register(
+	const struct simple_counter_count *const simple_count,
+	struct counter_count *const count)
+{
+	const struct simple_counter_count_ext *const simple_ext =
+		simple_count->ext;
+	const size_t num_ext = simple_count->num_ext;
+	struct counter_count_ext *ext;
+	size_t i;
+
+	/* Return early if no extensions */
+	if (!simple_ext || !num_ext)
+		return 0;
+
+	/* Allocate space for Counter Count extensions array */
+	ext = kmalloc_array(num_ext, sizeof(*ext), GFP_KERNEL);
+	if (!ext)
+		return -ENOMEM;
+
+	/* Register simple_counter_count_ext via counter_count_ext */
+	for (i = 0; i < num_ext; i++) {
+		ext[i].name = simple_ext[i].name;
+		ext[i].read = (simple_ext[i].read) ?
+			simple_counter_count_ext_read : NULL;
+		ext[i].write = (simple_ext[i].write) ?
+			simple_counter_count_ext_write : NULL;
+		ext[i].priv = simple_ext + i;
+	}
+
+	/* Register Counter Count extensions */
+	count->ext = ext;
+	count->num_ext = num_ext;
+
+	return 0;
+}
+
+static void simple_counter_counter_synapse_unregister(
+	const struct counter_count *const count)
+{
+	kfree(count->synapses);
+}
+
+static int simple_counter_counter_count_init(
+	struct counter_count *const count,
+	struct simple_counter_count *const simple_count,
+	struct counter_signal *const signal)
+{
+	int err;
+
+	count->id = simple_count->id;
+	count->name = simple_count->name;
+	count->functions = simple_counter_function_names;
+	count->num_functions = ARRAY_SIZE(simple_counter_function_names);
+	count->priv = simple_count;
+
+	/* Register Counter Synapse */
+	err = simple_counter_counter_synapse_register(signal, count);
+	if (err)
+		return err;
+
+	/* Register Counter Count extensions */
+	err = simple_counter_counter_count_ext_register(simple_count, count);
+	if (err)
+		goto err_unregister_synapse;
+
+	return 0;
+
+err_unregister_synapse:
+	simple_counter_counter_synapse_unregister(count);
+	return err;
+}
+
+static void simple_counter_counter_count_ext_unregister(
+	const struct counter_count *const count)
+{
+	kfree(count->ext);
+}
+
+static void simple_counter_counter_count_free(
+	const struct counter_count *const count)
+{
+	simple_counter_counter_count_ext_unregister(count);
+	simple_counter_counter_synapse_unregister(count);
+}
+
+static int simple_counter_counter_counts_register(
+	const struct simple_counter_device *const counter)
+{
+	struct counter_device *const counter_dev = counter->counter_dev;
+	struct counter_count *counts;
+	const size_t num_counts = counter->num_counts;
+	size_t i;
+	struct simple_counter_count *const simple_counts = counter->counts;
+	struct counter_signal *const signals = counter_dev->signals;
+	int err;
+
+	/* Allocate space for counts array */
+	counts = kcalloc(num_counts, sizeof(*counts), GFP_KERNEL);
+	if (!counts)
+		return -ENOMEM;
+
+	/* Initialize Counts */
+	for (i = 0; i < num_counts; i++) {
+		err = simple_counter_counter_count_init(counts + i,
+			simple_counts + i, signals + i);
+		if (err)
+			goto err_free_counts;
+	}
+
+	/* Register Counts to Counter device container */
+	counter_dev->counts = counts;
+	counter_dev->num_counts = num_counts;
+
+	return 0;
+
+err_free_counts:
+	while (i--)
+		simple_counter_counter_count_free(counts + i);
+	kfree(counts);
+	return err;
+}
+
+static void simple_counter_counter_signals_unregister(
+	const struct counter_device *const counter_dev)
+{
+	const struct counter_signal *const signals = counter_dev->signals;
+	size_t num_signals = counter_dev->num_signals;
+
+	while (num_signals--)
+		kfree(signals[num_signals].ext);
+	kfree(signals);
+}
+
+static int simple_counter_counts_register(
+	struct simple_counter_device *const counter)
+{
+	const struct simple_counter_count *const simple_counts =
+		counter->counts;
+	const size_t num_counts = counter->num_counts;
+	int err;
+
+	/* At least one Count must be defined */
+	if (!simple_counts || !num_counts) {
+		pr_err("simple-counter: Simple Counter Counts undefined\n");
+		return -EINVAL;
+	}
+
+	/* Register Counter Signals */
+	err = simple_counter_counter_signals_register(counter);
+	if (err)
+		return err;
+
+	/* Register Counter Counts */
+	err = simple_counter_counter_counts_register(counter);
+	if (err)
+		goto err_unregister_signals;
+
+	return 0;
+
+err_unregister_signals:
+	simple_counter_counter_signals_unregister(counter->counter_dev);
+	return err;
+}
+
+static ssize_t simple_counter_device_ext_read(struct counter_device *dev,
+	void *priv, char *buf)
+{
+	const struct simple_counter_device_ext *const ext = priv;
+	struct simple_counter_device *const counter = dev->priv;
+
+	return ext->read(counter, ext->priv, buf);
+}
+
+static ssize_t simple_counter_device_ext_write(struct counter_device *dev,
+	void *priv, const char *buf, size_t len)
+{
+	const struct simple_counter_device_ext *const ext = priv;
+	struct simple_counter_device *const counter = dev->priv;
+
+	return ext->write(counter, ext->priv, buf, len);
+}
+
+static int simple_counter_device_ext_register(
+	struct simple_counter_device *const counter)
+{
+	const struct simple_counter_device_ext *const simple_ext = counter->ext;
+	const size_t num_ext = counter->num_ext;
+	struct counter_device_ext *ext;
+	size_t i;
+	struct counter_device *const counter_dev = counter->counter_dev;
+
+	/* Return early if no extensions */
+	if (!simple_ext || !num_ext)
+		return 0;
+
+	/* Allocate space for Counter device extensions array */
+	ext = kmalloc_array(num_ext, sizeof(*ext), GFP_KERNEL);
+	if (!ext)
+		return -ENOMEM;
+
+	/* Register simple_counter_device_ext via counter_device_ext */
+	for (i = 0; i < num_ext; i++) {
+		ext[i].name = simple_ext[i].name;
+		ext[i].read = (simple_ext[i].read) ?
+			simple_counter_device_ext_read : NULL;
+		ext[i].write = (simple_ext[i].write) ?
+			simple_counter_device_ext_write : NULL;
+		ext[i].priv = simple_ext + i;
+	}
+
+	/* Register Counter device extensions */
+	counter_dev->ext = ext;
+	counter_dev->num_ext = num_ext;
+
+	return 0;
+}
+
+static void simple_counter_counter_counts_unregister(
+	const struct counter_device *const counter)
+{
+	const struct counter_count *const counts = counter->counts;
+	size_t num_counts = counter->num_counts;
+
+	while (num_counts--)
+		simple_counter_counter_count_free(counts + num_counts);
+	kfree(counts);
+}
+
+static void simple_counter_counts_unregister(
+	const struct simple_counter_device *const counter)
+{
+	const struct counter_device *const counter_dev = counter->counter_dev;
+
+	simple_counter_counter_counts_unregister(counter_dev);
+	simple_counter_counter_signals_unregister(counter_dev);
+}
+
+/**
+ * simple_counter_register - register Simple Counter to the system
+ * @counter: pointer to Simple Counter to register
+ *
+ * This function registers a Simple Counter to the system. A sysfs "counter"
+ * directory will be created and populated with sysfs attributes correlating
+ * with the Simple Counter Signals, Synapses, and Counts respectively.
+ */
+int simple_counter_register(struct simple_counter_device *const counter)
+{
+	struct counter_device *counter_dev;
+	int err;
+
+	if (!counter)
+		return -EINVAL;
+
+	/* Allocate internal Counter container */

drivers/iio/counter/simple-counter.c line 592

Quoted 10 lines
drivers/iio/counter/simple-counter.c new file +10 -0
+	counter_dev = kzalloc(sizeof(*counter_dev), GFP_KERNEL);
+	if (!counter)
+		return -ENOMEM;
+	counter->counter_dev = counter_dev;
+
+	/* Configure internal Counter */
+	counter_dev->name = counter->name;
+	counter_dev->parent = counter->parent;
+	counter_dev->signal_read = (counter->signal_read) ?
+		simple_counter_signal_read : NULL;

Ah. This will make my below comment on taking this const tricky (at least for the generic counter).

What do you loose if you take the null check into the simple_counter wrappers rather than here?

Quoted 264 lines
drivers/iio/counter/simple-counter.c new file +142 -0
+	counter_dev->signal_write = (counter->signal_write) ?
+		simple_counter_signal_write : NULL;
+	counter_dev->count_read = (counter->count_read) ?
+		simple_counter_count_read : NULL;
+	counter_dev->count_write = (counter->count_write) ?
+		simple_counter_count_write : NULL;
+	counter_dev->function_get = (counter->function_get) ?
+		simple_counter_function_get : NULL;
+	counter_dev->function_set = (counter->function_set) ?
+		simple_counter_function_set : NULL;
+	counter_dev->action_get = (counter->action_get) ?
+		simple_counter_action_get : NULL;
+	counter_dev->action_set = (counter->action_set) ?
+		simple_counter_action_set : NULL;
+	counter_dev->priv = counter;
+
+	/* Register Simple Counter Counts */
+	err = simple_counter_counts_register(counter);
+	if (err)
+		goto err_free_counter_dev;
+
+	/* Register Simple Counter device extension attributes */
+	err = simple_counter_device_ext_register(counter);
+	if (err)
+		goto err_unregister_counts;
+
+	/* Register internal Counter to the system */
+	err = counter_register(counter_dev);
+	if (err)
+		goto err_free_ext;
+
+	return 0;
+
+err_free_ext:
+	kfree(counter_dev->ext);
+err_unregister_counts:
+	simple_counter_counts_unregister(counter);
+err_free_counter_dev:
+	kfree(counter_dev);
+	return err;
+}
+EXPORT_SYMBOL(simple_counter_register);
+
+/**
+ * simple_counter_unregister - unregister Simple Counter from the system
+ * @counter: pointer to Simple Counter to unregister
+ *
+ * The Simple Counter is unregistered from the system; all allocated memory is
+ * freed.
+ */
+void simple_counter_unregister(struct simple_counter_device *const counter)
+{
+	struct counter_device *counter_dev;
+
+	if (!counter)
+		return;
+
+	counter_dev = counter->counter_dev;
+
+	counter_unregister(counter_dev);
+
+	kfree(counter_dev->ext);
+	simple_counter_counts_unregister(counter);
+	kfree(counter_dev);
+}
+EXPORT_SYMBOL(simple_counter_unregister);
+
+static void devm_simple_counter_unreg(struct device *dev, void *res)
+{
+	simple_counter_unregister(*(struct simple_counter_device **)res);
+}
+
+/**
+ * devm_simple_counter_register - Resource-managed simple_counter_register
+ * @dev: device to allocate simple_counter_device for
+ * @counter: pointer to Simple Counter to register
+ *
+ * Managed simple_counter_register. The Simple Counter registered with this
+ * function is automatically unregistered on driver detach. This function calls
+ * simple_counter_register internally. Refer to that function for more
+ * information.
+ *
+ * If an Simple Counter registered with this function needs to be unregistered
+ * separately, devm_simple_counter_unregister must be used.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int devm_simple_counter_register(struct device *dev,
+	struct simple_counter_device *const counter)
+{
+	struct simple_counter_device **ptr;
+	int ret;
+
+	ptr = devres_alloc(devm_simple_counter_unreg, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+
+	ret = simple_counter_register(counter);
+	if (!ret) {
+		*ptr = counter;
+		devres_add(dev, ptr);
+	} else
+		devres_free(ptr);
+
+	return ret;
+}
+EXPORT_SYMBOL(devm_simple_counter_register);
+
+static int devm_simple_counter_match(struct device *dev, void *res, void *data)
+{
+	struct simple_counter_device **r = res;
+
+	if (!r || !*r) {
+		WARN_ON(!r || !*r);
+		return 0;
+	}
+
+	return *r == data;
+}
+
+/**
+ * devm_simple_counter_unregister - Resource-managed simple_counter_unregister
+ * @dev: device this simple_counter_device belongs to
+ * @counter: the Simple Counter associated with the device
+ *
+ * Unregister Simple Counter registered with devm_simple_counter_register.
+ */
+void devm_simple_counter_unregister(struct device *dev,
+	struct simple_counter_device *const counter)
+{
+	int rc;
+
+	rc = devres_release(dev, devm_simple_counter_unreg,
+		devm_simple_counter_match, counter);
+	WARN_ON(rc);
+}
+EXPORT_SYMBOL(devm_simple_counter_unregister);
+
+MODULE_AUTHOR("William Breathitt Gray <[email protected]>");
+MODULE_DESCRIPTION("Simple Counter interface");
+MODULE_LICENSE("GPL v2");
include/linux/iio/counter.h +114 -0
index 070ed8fd53fb..0967ea2a9bef 100644
@@ -236,4 +236,203 @@ extern int devm_counter_register(struct device *dev,
 extern void devm_counter_unregister(struct device *dev,
 	struct counter_device *const counter);
 
+struct simple_counter_device;
+struct simple_counter_signal;
+
+/**
+ * struct simple_counter_signal_ext - Simple Counter Signal extension
+ * @name:	[DRIVER] attribute name
+ * @read:	[DRIVER] read callback for this attribute; may be NULL
+ * @write:	[DRIVER] write callback for this attribute; may be NULL
+ * @priv:	[DRIVER] data private to the driver
+ */
+struct simple_counter_signal_ext {
+	const char	*name;
+	ssize_t		(*read)(struct simple_counter_device *counter,
+				struct simple_counter_signal *signal,
+				void *priv, char *buf);
+	ssize_t		(*write)(struct simple_counter_device *counter,
+				struct simple_counter_signal *signal,
+				void *priv, const char *buf, size_t len);
+	void		*priv;
+};
+
+/**
+ * struct simple_counter_signal - Simple Counter Signal node
+ * @id:		[DRIVER] unique ID used to identify signal
+ * @name:	[DRIVER] device-specific signal name
+ * @ext:	[DRIVER] optional array of Simple Counter Signal extensions
+ * @num_ext:	[DRIVER] number of Simple Counter Signal extensions specified in
+ *		@ext
+ * @priv:	[DRIVER] optional private data supplied by driver
+ */
+struct simple_counter_signal {
+	int		id;
+	const char	*name;
+
+	const struct simple_counter_signal_ext	*ext;
+	size_t					num_ext;
+
+	void	*priv;
+};
+
+enum simple_counter_signal_level {
+	SIMPLE_COUNTER_SIGNAL_LOW = 0,
+	SIMPLE_COUNTER_SIGNAL_HIGH
+};
+
+struct simple_counter_count;
+
+enum simple_counter_function {
+	SIMPLE_COUNTER_FUNCTION_INCREASE = 0,
+	SIMPLE_COUNTER_FUNCTION_DECREASE
+};
+
+enum simple_counter_action {
+	SIMPLE_COUNTER_ACTION_NONE = 0,
+	SIMPLE_COUNTER_ACTION_RISING_EDGE,
+	SIMPLE_COUNTER_ACTION_FALLING_EDGE,
+	SIMPLE_COUNTER_ACTION_BOTH_EDGES
+};
+
+/**
+ * struct simple_counter_count_ext - Simple Counter Count extension
+ * @name:	[DRIVER] attribute name
+ * @read:	[DRIVER] read callback for this attribute; may be NULL
+ * @write:	[DRIVER] write callback for this attribute; may be NULL
+ * @priv:	[DRIVER] data private to the driver
+ */
+struct simple_counter_count_ext {
+	const char	*name;
+	ssize_t		(*read)(struct simple_counter_device *counter,
+				struct simple_counter_count *count, void *priv,
+				char *buf);
+	ssize_t		(*write)(struct simple_counter_device *counter,
+				struct simple_counter_count *count, void *priv,
+				const char *buf, size_t len);
+	void		*priv;
+};
+
+/**
+ * struct simple_counter_count - Simple Counter Count node
+ * @id:		[DRIVER] unique ID used to identify Count
+ * @name:	[DRIVER] device-specific Count name
+ * @function:	[DRIVER] current function mode
+ * @action:	[DRIVER] current action mode
+ * @signal:	[DRIVER] associated signal
+ * @ext:	[DRIVER] optional array of Simple Counter Count extensions
+ * @num_ext:	[DRIVER] number of Simple Counter Count extensions specified in
+ *		@ext
+ * @priv:	[DRIVER] optional private data supplied by driver
+ */
+struct simple_counter_count {
+	int				id;
+	const char			*name;
+	enum simple_counter_function	function;
+	enum simple_counter_action	action;
+
+	struct simple_counter_signal	signal;
+
+	const struct simple_counter_count_ext	*ext;
+	size_t					num_ext;
+
+	void	*priv;
+};
+
+/**
+ * struct simple_counter_device_ext - Simple Counter device extension
+ * @name:	[DRIVER] attribute name
+ * @read:	[DRIVER] read callback for this attribute; may be NULL
+ * @write:	[DRIVER] write callback for this attribute; may be NULL
+ * @priv:	[DRIVER] data private to the driver
+ */
+struct simple_counter_device_ext {
+	const char	*name;
+	ssize_t		(*read)(struct simple_counter_device *counter,
+				void *priv, char *buf);

include/linux/iio/counter.h extern int devm_counter_register(struct device *dev, · line 362

Quoted 10 lines
include/linux/iio/counter.h +10 -0
+	ssize_t		(*write)(struct simple_counter_device *counter,
+				void *priv, const char *buf, size_t len);
+	void		*priv;
+};
+
+/**
+ * struct simple_counter_device - Simple Counter data structure
+ * @name:		[DRIVER] name of the device
+ * @parent:		[DRIVER] optional parent device providing the counters
+ * @counter_dev:	[INTERN] internal Counter container

Same comment as before. Just mark the on the drive shouldn't play with.

Quoted 25 lines
include/linux/iio/counter.h +25 -0
+ * @signal_read:	[DRIVER] read callback for Signal attribute; may be
+ *			NULL. Returns 0 on success and negative error code on
+ *			error. The respective Signal's returned	level should be
+ *			passed back via the level parameter.
+ * @signal_write:	[DRIVER] write callback for Signal attribute; may be
+ *			NULL
+ * @count_read:		[DRIVER] read callback for Count attribute; may be NULL.
+ *			Returns 0 on success and negative error code on error.
+ *			The respective Count's returned value should be passed
+ *			back via the val parameter.
+ * @count_write:	[DRIVER] write callback for Count attribute; may be NULL
+ * @function_get:	[DRIVER] function to get the current count function
+ *			mode. Returns 0 on success and negative error code on
+ *			error. The respective Count's returned function mode
+ *			should be passed back via the function parameter.
+ * @function_set:	[DRIVER] function to set the count function mode
+ * @action_get:		[DRIVER] function to get the current action mode.
+ *			Returns 0 on success and negative error code on error.
+ *			The respective Signal's returned action mode should be
+ *			passed back via the action parameter.
+ * @action_set:		[DRIVER] function to set the action mode
+ * @counts:		[DRIVER] array of Simple Counter Counts
+ * @num_counts:		[DRIVER] number of Simple Counter Counts specified in
+ *			@counts
+ * @ext:		[DRIVER] optional array of Simple Counter device

include/linux/iio/counter.h extern int devm_counter_register(struct device *dev, · line 397

Quoted 10 lines
include/linux/iio/counter.h +10 -0
+ *			extensions
+ * @num_ext:		[DRIVER] number of Simple Counter device extensions
+ *			specified in @ext
+ * @priv:		[DRIVER] optional private data supplied by driver
+ */
+struct simple_counter_device {
+	const char		*name;
+	struct device		*parent;
+	struct counter_device	*counter_dev;
+

Not sure why I didn't notice before, but presumably all the below are effectively const function pointers?
Lift them out to an ops structure as that'll let the order randomization stuff play with them safely (security measure). Also lets us take a large block of this constant.

Adds a small level of indirection but worth it for the gains.

Quoted 41 lines
include/linux/iio/counter.h +40 -0
+	int	(*signal_read)(struct simple_counter_device *counter,
+			struct simple_counter_signal *signal,
+			enum simple_counter_signal_level *level);
+	int	(*signal_write)(struct simple_counter_device *counter,
+			struct simple_counter_signal *signal,
+			enum simple_counter_signal_level level);
+	int	(*count_read)(struct simple_counter_device *counter,
+			struct simple_counter_count *count, long *val);
+	int	(*count_write)(struct simple_counter_device *counter,
+			struct simple_counter_count *count, long val);
+	int	(*function_get)(struct simple_counter_device *counter,
+			struct simple_counter_count *count,
+			enum simple_counter_function *function);
+	int	(*function_set)(struct simple_counter_device *counter,
+			struct simple_counter_count *count,
+			enum simple_counter_function function);
+	int	(*action_get)(struct simple_counter_device *counter,
+			struct simple_counter_count *count,
+			enum simple_counter_action *action);
+	int	(*action_set)(struct simple_counter_device *counter,
+			struct simple_counter_count *count,
+			enum simple_counter_action action);
+
+	struct simple_counter_count	*counts;
+	size_t				num_counts;
+
+	const struct simple_counter_device_ext	*ext;
+	size_t					num_ext;
+
+	void	*priv;
+};
+
+extern int simple_counter_register(struct simple_counter_device *const counter);
+extern void simple_counter_unregister(
+	struct simple_counter_device *const counter);
+extern int devm_simple_counter_register(struct device *dev,
+	struct simple_counter_device *const counter);
+extern void devm_simple_counter_unregister(struct device *dev,
+	struct simple_counter_device *const counter);
+
 #endif /* _COUNTER_H_ */
#9 lore raw

PATCH v4 5/11 counter: Documentation: Add Simple Counter sysfs documentation

In reply to William Breathitt Gray

This patch adds standard documentation for the userspace sysfs attributes of the Simple Counter interface.

---
 .../ABI/testing/sysfs-bus-counter-simple-sysfs     | 61 ++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs
Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs new file +61 -0
new file mode 100644
index 000000000000..e1f32c64c667
@@ -0,0 +1,61 @@
+What:		/sys/bus/counter/devices/counterX/countY
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Count data of Count Y. This is a signed integer value that
+		represents the accumulated count.
+
+What:		/sys/bus/counter/devices/counterX/countY_function
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Count function mode of Count Y. Count function evaluation is
+		triggered by conditions specified by the countY_signalZ_action
+		attributes. Two count function modes are available: increase and
+		decrease.
+
+		Increase:
+			Accumulated count is incremented.
+
+		Decrease:
+			Accumulated count is decremented.
+
+What:		/sys/bus/counter/devices/counterX/countY_max
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Count Y count data maximum value.
+
+What:		/sys/bus/counter/devices/counterX/countY_min
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Count Y count data minimum value.
+
+What:		/sys/bus/counter/devices/counterX/countY_signalZ_action
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Action mode of Count Y for Signal Z. This attribute indicates
+		the condition of Signal Z that triggers the count function
+		evaluation for Count Y. Four action modes are available: none,
+		rising edge, falling edge, and both edges.
+
+		None:
+			Signal does not trigger the count function.
+
+		Rising Edge:
+			Low state transitions to High state.
+
+		Falling Edge:
+			High state transitions to Low state.
+
+		Both Edges:
+			Any state transition.
+
+What:		/sys/bus/counter/devices/counterX/signalY
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Signal data of Signal Y. This is the respective input level
+		represented by two available states: low and high.
Signature · 1 line
2.15.1
maintainer
#10 lore raw

Re: [PATCH v4 05/11] counter: Documentation: Add Simple Counter sysfs documentation

Quoted 26 lines · On Thu, 14 Dec 2017 15:51:43 -0500 William Breathitt Gray…

This patch adds standard documentation for the userspace sysfs attributes of the Simple Counter interface.

---
 .../ABI/testing/sysfs-bus-counter-simple-sysfs     | 61 ++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs
Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs new file +11 -0
new file mode 100644
index 000000000000..e1f32c64c667
@@ -0,0 +1,61 @@
+What:		/sys/bus/counter/devices/counterX/countY
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Count data of Count Y. This is a signed integer value that
+		represents the accumulated count.
+
+What:		/sys/bus/counter/devices/counterX/countY_function
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:

Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs line 21

Quoted 10 lines
Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs new file +10 -0
+		Count function mode of Count Y. Count function evaluation is
+		triggered by conditions specified by the countY_signalZ_action
+		attributes. Two count function modes are available: increase and
+		decrease.
+
+		Increase:
+			Accumulated count is incremented.
+
+		Decrease:
+			Accumulated count is decremented.

Ah, so the specifics are in these files. Fair enough I suppose though in that case. Perhaps add a note where relevant in the generic file to say this.

Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs line 27

Quoted 6 lines
Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs new file +6 -0
+
+What:		/sys/bus/counter/devices/counterX/countY_max
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Count Y count data maximum value.

What does this mean? Does it wrap here, or stop here? Needs defining.

Quoted 5 lines
Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs new file +5 -0
+
+What:		/sys/bus/counter/devices/counterX/countY_min
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:

Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs line 42

Quoted 10 lines
Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs new file +10 -0
+		Count Y count data minimum value.
+
+What:		/sys/bus/counter/devices/counterX/countY_signalZ_action
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Action mode of Count Y for Signal Z. This attribute indicates
+		the condition of Signal Z that triggers the count function
+		evaluation for Count Y. Four action modes are available: none,
+		rising edge, falling edge, and both edges.

I'd put the values in quotes to make it easy to isolate them.

Quoted 19 lines
Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs new file +19 -0
+
+		None:
+			Signal does not trigger the count function.
+
+		Rising Edge:
+			Low state transitions to High state.
+
+		Falling Edge:
+			High state transitions to Low state.
+
+		Both Edges:
+			Any state transition.
+
+What:		/sys/bus/counter/devices/counterX/signalY
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Signal data of Signal Y. This is the respective input level
+		represented by two available states: low and high.
#11 lore raw

PATCH v4 6/11 docs: Add Simple Counter interface documentation

In reply to William Breathitt Gray

This patch adds high-level documentation about the Simple Counter interface.

---
 Documentation/driver-api/iio/index.rst          |   1 +
 Documentation/driver-api/iio/simple-counter.rst | 393 ++++++++++++++++++++++++
 2 files changed, 394 insertions(+)
 create mode 100644 Documentation/driver-api/iio/simple-counter.rst
Documentation/driver-api/iio/index.rst +1 -0
index e6c5b75c2e03..60e17f16cfb8 100644
@@ -16,3 +16,4 @@ Contents:
    triggers
    triggered-buffers
    generic-counter
+   simple-counter
Documentation/driver-api/iio/simple-counter.rst new file +393 -0

393 lines not on this page · raw message

Signature · 1 line
2.15.1
maintainer
#12 lore raw

Re: [PATCH v4 06/11] docs: Add Simple Counter interface documentation

Quoted 4 lines · On Thu, 14 Dec 2017 15:51:55 -0500 William Breathitt Gray…

This patch adds high-level documentation about the Simple Counter interface.

On small suggestion inline.

Jonathan

Quoted 67 lines
---
 Documentation/driver-api/iio/index.rst          |   1 +
 Documentation/driver-api/iio/simple-counter.rst | 393 ++++++++++++++++++++++++
 2 files changed, 394 insertions(+)
 create mode 100644 Documentation/driver-api/iio/simple-counter.rst
Documentation/driver-api/iio/index.rst +1 -0
index e6c5b75c2e03..60e17f16cfb8 100644
@@ -16,3 +16,4 @@ Contents:
    triggers
    triggered-buffers
    generic-counter
+   simple-counter
Documentation/driver-api/iio/simple-counter.rst new file +46 -0
new file mode 100644
index 000000000000..fa34f689e99f
@@ -0,0 +1,393 @@
+========================
+Simple Counter Interface
+========================
+
+Introduction
+============
+
+The most basic counter device may be expressed as a single Count
+associated with a single Signal via a single Synapse. This is a popular
+type of Counter implemented by hardware devices, and also what commonly
+comes to mind when one thinks of a "counter device." This driver API
+provides a basic Counter interface and standard of interaction and
+exposure for these simple counter devices. The Simple Counter interface
+enables drivers to support and expose simple counter devices in a more
+apt and well-defined way, without the hassles and imprecisions of
+utilizing a more generic interface.
+
+Theory
+======
+
+The Simple Counter interface may be considered a subclass of the
+Generic Counter interface; the same paradigm core components apply:
+Counts, Signals, and Synapses. However, the Simple Counter interface
+goes a bit further and defines aspects of those core components to
+properly represent Simple Counter devices.
+
+The three core components of a Simple Counter:
+
+        COUNT
+        -----
+        A Count represents the count data for a set of Signals. The
+        count data for a Simple Counter is a signed integer representing
+        the accumulated count of Simple Signal action conditions.
+
+        A Count has a count function mode which represents the update
+        behavior for the count data. The following two count function
+        modes are possible for a Simple Count:
+
+                * Increase:
+                        Accumulated count is incremented.
+                * Decrease:
+                        Accumulated count is decremented.
+
+        A Simple Count has one associated Simple Signal.
+
+        SIGNAL

Documentation/driver-api/iio/simple-counter.rst line 56

Quoted 10 lines
Documentation/driver-api/iio/simple-counter.rst new file +10 -0
+        ------
+        A Signal represents a counter input data; this is the data that
+        is typically analyzed by the counter to determine the count
+        data. A Simple Signal represents a counter input line with two
+        possible states:
+
+                * Low
+                * High
+
+        A Simple Signal is associated to a Simple Count.

Might be worth noting that there may be no visibility of this to software.

Quoted 63 lines
Documentation/driver-api/iio/simple-counter.rst new file +63 -0
+
+        SYNAPSE
+        -------
+        A Synapse represents the association of a Signal with a
+        respective Count. Signal data affects respective Count data, and
+        the Synapse represents this relationship.
+
+        The Synapse action mode specifies the Signal data condition
+        which triggers the respective Count's count function evaluation
+        to update the count data. There are four possible action modes
+        for a Simple Counter:
+
+                * None:
+                        Signal does not trigger the count function.
+                * Rising Edge:
+                        Low state transitions to High state.
+                * Falling Edge:
+                        High state transitions to Low state.
+                * Both Edges:
+                        Any state transition.
+
+Paradigm
+========
+
+Simple Counter devices consist of a single Count associated with a
+single Signal via a single Synapse. Take for example a counter device
+which simply accumulates a count of rising edges on a source input line.
+
+        Count                Synapse        Signal
+        -----                -------        ------
++---------------------+
+| Data: Count         |    Rising Edge     ________
+| Function: Increase  |  <-------------   / Source \
+|                     |                  ____________
++---------------------+
+
+In this example, the Signal is a source input line with a pulsing
+voltage, while the Count is a persistent count value which is repeatedly
+incremented. The Signal is associated with the respective Count via a
+Synapse. The increase function is triggered by the Signal data condition
+specified by the Synapse -- in this case a rising edge condition on the
+voltage input line.
+
+In summary, the simple counter device existence and behavior is aptly
+represented by respective Count, Signal, and Synapse components: e.g. a
+rising edge condition triggers an increase function on an accumulating
+count datum.
+
+Userspace Interface
+===================
+
+Several sysfs attributes are generated by the Simple Counter interface,
+and reside under the /sys/bus/counter/devices/counterX directory, where
+counterX refers to the respective counter device. Please see
+Documentation/ABI/testing/sys-bus-counter-simple-sysfs for detailed
+information on each Simple Counter interface sysfs attribute.
+
+In addition, several sysfs attributes are generated by the underlying
+Generic Counter interface, and also reside under the
+/sys/bus/counter/devices/counterX directory, where counterX refers to
+the respective counter device. Please see
+Documentation/ABI/testing/sys-bus-counter-generic-sysfs for detailed
+information on each Generic Counter interface sysfs attribute.

Documentation/driver-api/iio/simple-counter.rst

Quoted 10 lines
Documentation/driver-api/iio/simple-counter.rst new file +10 -0
+
+Through these sysfs attributes, programs and scripts may interact with
+the Simple Counter paradigm Counts, Signals, and Synapses of respective
+counter devices.
+
+Driver API
+==========
+
+Driver authors may utilize the Simple Counter interface in their code
+by including the include/linux/iio/counter.h header file. 

I would have a separate header file for the simple counter that itself includes counter.h. Thus devices not using simple counter don't get to see its functions etc. You might not even build it for example.

Quoted 265 lines

This header

Documentation/driver-api/iio/simple-counter.rst new file +264 -0
+file provides several core data structures and function prototypes for
+defining a simple counter.
+
+
+struct simple_counter_signal_ext
+--------------------------------
+
+This structure defines a Simple Counter Signal extension attribute.
+These attributes expose auxiliary configuration and functionality
+specific to the respective Simple Counter Signal.
+
+        name:   attribute name
+        read:   read callback for this attribute; may be NULL
+        write:  write callback for this attribute; may be NULL
+        priv:   data private to the driver
+
+struct simple_counter_signal
+----------------------------
+
+This structure defines a Simple Counter Signal component. Typically,
+this will correlate with an input channel on a physical counter device.
+This structure is the simplest of the Simple Counter paradigm core
+components to define with only two structure members which require
+explicit configuration:
+
+        id:             unique ID used to identify signal
+        name:           device-specific signal name
+        ext:            optional array of Simple Counter Signal
+                        extensions
+        num_ext:        number of Simple Counter Signal extensions
+                        specified in @ext
+        priv:           optional private data supplied by driver
+
+enum simple_counter_signal_level
+--------------------------------
+
+This enum defines enumeration constants to represent the possible Simple
+Signal data level states.
+
+        SIMPLE_COUNTER_SIGNAL_LOW:      Low
+        SIMPLE_COUNTER_SIGNAL_HIGH:     High
+
+enum simple_counter_function
+----------------------------
+
+This enum defines enumeration constants to represent the possible Simple
+Counter count function modes.
+
+        SIMPLE_COUNTER_FUNCTION_INCREASE:       Increase
+        SIMPLE_COUNTER_FUNCTION_DECREASE:       Decrease
+
+enum simple_counter_action
+--------------------------
+
+This enum defines enumeration constants to represent the possible Simple
+Counter action modes.
+
+        SIMPLE_COUNTER_ACTION_NONE:             None
+        SIMPLE_COUNTER_ACTION_RISING_EDGE:      Rising Edge
+        SIMPLE_COUNTER_ACTION_FALLING_EDGE:     Falling Edge
+        SIMPLE_COUNTER_ACTION_BOTH_EDGES:       Both Edges
+
+struct simple_counter_count_ext
+-------------------------------
+
+This structure defines a Simple Counter Count extension attribute. These
+attributes expose auxiliary configuration and functionality specific to
+the respective Simple Counter Count.
+
+        name:   attribute name
+        read:   read callback for this attribute; may be NULL
+        write:  write callback for this attribute; may be NULL
+        priv:   data private to the driver
+
+struct simple_counter_count
+---------------------------
+
+This structure defines a Simple Counter Count component. Typically, this
+will correlate with the read data (the "count" value) provided by a
+physical counter device. This structure requires the explicit
+configuration of an ID, name, and the Simple Signal associated with this
+Simple Count.
+
+        id:             unique ID used to identify Count
+        name:           device-specific Count name
+        function:       current function mode
+        action:         current action mode
+        signal:         associated signal
+        ext:            optional array of Simple Counter Count
+                        extensions
+        num_ext:        number of Simple Counter Count extensions
+                        specified in @ext
+        priv:           optional private data supplied by driver
+
+struct simple_counter_device_ext
+--------------------------------
+
+This structure defines a Simple Counter extension attribute. These
+attributes expose auxiliary configuration and functionality specific to
+the respective Simple Counter.
+
+        name:   attribute name
+        read:   read callback for this attribute; may be NULL
+        write:  write callback for this attribute; may be NULL
+        priv:   data private to the driver
+
+struct simple_counter_device
+----------------------------
+
+This is the main data structure for a Simple Counter device. Access to
+all respective Counts, Signals, and Synapses is possible from this
+structure. This structure requires the configuration of a name and
+Simple Counter Counts:
+
+        name:           name of the device
+        parent:         optional parent device providing the counters
+        signal_read:    read callback for Signal attribute; may be NULL.
+                        Returns 0 on success and negative error code on
+                        error. The respective Signal's returned level
+                        should be passed back via the level parameter.
+        signal_write:   write callback for Signal attribute; may be NULL
+        count_read:     read callback for Count attribute; may be NULL.
+                        Returns 0 on success and negative error code on
+                        error. The respective Count's returned value
+                        should be passed back via the val parameter.
+        count_write:    write callback for Count attribute; may be NULL
+        function_get:   function to get the current count function mode.
+                        Returns 0 on success and negative error code on
+                        error. The respective Count's returned function
+                        mode should be passed back via the function
+                        parameter.
+        function_set:   function to set the count function mode
+        action_get:     function to get the current action mode. Returns
+                        0 on success and negative error code on error.
+                        The respective Signal's returned action mode
+                        should be passed back via the action parameter.
+        action_set:     function to set the action mode
+        counts:         array of Simple Counter Counts
+        num_counts:     number of Simple Counter Counts specified in
+                        @counts
+        ext:            optional array of Simple Counter device
+                        extensions
+        num_ext:        number of Simple Counter device extensions
+                        specified in @ext
+        priv:           optional private data supplied by driver
+
+Registration functions
+----------------------
+
+A simple counter device is registered to the system by passing the
+respective initialized simple_counter_device structure to the
+simple_counter_register function; similarly, the
+simple_counter_unregister function unregisters the respective
+Simple Counter. The devm_simple_counter_register and
+devm_simple_counter_unregister functions serve as device memory-managed
+versions of the simple_counter_register and simple_counter_unregister
+functions respectively.
+
+Implementation
+==============
+
+To use the Simple Counter interface, create an array of
+simple_counter_count structures to represent the desired Counts and
+Signals of the counter device. The simple_counter_count structure has a
+Simple Signal member that represents the associated Signal, so only the
+Simple Counts need to be explicited allocated -- the associated Simple
+Signal members are simply populated with the respective desired
+definitions. The defined simple_counter_count array may then be added
+to a simple_counter_device structure for registration to the system.
+
+     Simple Count                    Count               Signal
+     ------------                    -----               ------
++---------------------+      +--------------------+
+| Data: Count         | ---> | Data: Count        |
+| Function: Increase  |      | Function: Increase |
+|                     |      +--------------------+
+|                     |
++---------------------+                                 ________
+| Signal: Source      | ---------------------------->  / Source \
+|                     |                               ____________
++---------------------+
+
+Driver callbacks should be provided to the simple_counter_device
+structure in order to communicate with the device: to read and write
+various Signals and Counts, and to set and get the "action mode" and
+"function mode" for various Synapses and Counts respectively.
+
+A defined simple_counter_device structure may be registered to the
+system by passing it to the simple_counter_register function, and
+unregistered by passing it to the simple_counter_unregister function.
+Similarly, the devm_simple_counter_register and
+devm_simple_counter_unregister functions may be used if device
+memory-managed registration is desired.
+
+Extension sysfs attributes can be created for auxiliary functionality
+and data by passing in defined simple_counter_device_ext,
+simple_counter_count_ext, and simple_counter_signal_ext structures. In
+these cases, the simple_counter_device_ext structure is used for global
+configuration of the respective Counter device, while the
+simple_counter_count_ext and simple_counter_signal_ext structures allow
+for auxiliary exposure and configuration of a specific Count or Signal
+respectively.
+
+Architecture
+============
+
+The Simple Counter interface is a subclass of the Generic Counter
+interface, and the Simple Counter interface functions serve as mappings
+onto the Generic Counter interface functions to simplify and aptly
+define support for simple counter devices.
+
+In this vein, the Generic Counter interface functions are ultimately
+called when the Simple Counter interface functions are utilized. For
+more information on the architecture of the Generic Counter interface,
+please refer to the Documentation/driver-api/iio/generic-counter.rst
+file.
+
+Simple Counter devices are registered to the system via the
+simple_counter_register function, and later removed via the
+simple_counter_unregister function. The simple_counter_register function
+will allocate a counter_device structure, populate it with the required
+Generic Counter structures and data required to represent the Simple
+Counter components, and register it to the system via a counter_register
+call.
+
+  _______________________       +-------------------------+
+ / simple_counter_device \  --> | simple_counter_register |
+___________________________     +-------------------------+
+                                  |
+   +------------------------------+
+   |
+   V
+  ________________       +------------------+
+ / counter_device \  --> | counter_register |
+____________________     +------------------+
+
+The signal_read/signal_write driver callbacks, the
+count_read/count_write and function_get/function_set driver callbacks,
+and the action_get/action_set driver callbacks are mapped to the
+allocated internal counter_device structure via appropriate hook
+functions.
+
+        Simple Counter  Remap Function                  Generic Counter
+        --------------  --------------                  ---------------
+
+        signal_read     simple_counter_signal_read      signal_read
+        signal_write    simple_counter_signal_write     signal_write
+        count_read      simple_counter_count_read       count_read
+        count_write     simple_counter_count_write      count_write
+        function_get    simple_counter_function_get     function_get
+        function_set    simple_counter_function_set     function_set
+        action_get      simple_counter_action_get       action_get
+        action_set      simple_counter_action_set       action_set
+
+This is how Generic Counter interface sysfs attributes are inherited and
+extended by the Simple Counter interface. If a driver callback is left
+undefined, then the respective read/write permission is left disabled
+for the relevant attributes.
+
+Similarly, simple_counter_device_ext, simple_counter_count_ext, and
+simple_counter_signal_ext structures are mapped to respective
+counter_device_ext, counter_count_ext, and counter_signal_ext structures
+via appropriate hook functions, and then added to the allocated internal
+counter_device structure for registration.
#13 lore raw

PATCH v4 7/11 counter: Add dummy counter driver

In reply to William Breathitt Gray

This patch introduces the dummy counter driver. The dummy counter driver serves as a reference implementation of a driver that utilizes the Simple Counter interface.

Writing "low" and "high" to the Signal attributes allows a user to simulate a typical Simple Counter Signal input stream for evaluation; the Counter will evaluate the Signal data based on the respective action mode for the associated Signal, and trigger the associated count function specified by the respective Count's function mode. The current Count value may be read, and the Count value preset by a write.

The Count max and min attributes serve to configure respective value ceiling and value floor for each desired Count.

---
 drivers/iio/counter/Kconfig         |  15 ++
 drivers/iio/counter/Makefile        |   1 +
 drivers/iio/counter/dummy-counter.c | 308 ++++++++++++++++++++++++++++++++++++
 3 files changed, 324 insertions(+)
 create mode 100644 drivers/iio/counter/dummy-counter.c
drivers/iio/counter/Kconfig +15 -0
index 6b9a43180d2c..9d7dae137f9c 100644
@@ -30,6 +30,21 @@ config 104_QUAD_8
 	  The base port addresses for the devices may be configured via the base
 	  array module parameter.
 
+config DUMMY_COUNTER
+	tristate "Dummy counter driver"
+	help
+	  Select this option to enable the dummy counter driver. The dummy
+	  counter driver serves as a reference implementation of a driver that
+	  utilizes the Generic Counter interface.
+
+	  Writing "low" and "high" to the Signal attributes allows a user to
+	  simulate a typical Simple Counter Signal input stream for evaluation;
+	  the Counter will evaluate the Signal data based on the respective
+	  trigger mode for the associated Signal, and trigger the associated
+	  counter function specified by the respective function mode. The
+	  current Value value may be read, and the Value value preset by a
+	  write.
+
 config STM32_LPTIMER_CNT
 	tristate "STM32 LP Timer encoder counter driver"
 	depends on (MFD_STM32_LPTIMER || COMPILE_TEST) && IIO
drivers/iio/counter/Makefile +1 -0
index 7450dee97446..febd2884b474 100644
@@ -9,4 +9,5 @@ counter-$(CONFIG_COUNTER) += generic-counter.o
 counter-$(CONFIG_COUNTER) += simple-counter.o
 
 obj-$(CONFIG_104_QUAD_8)	+= 104-quad-8.o
+obj-$(CONFIG_DUMMY_COUNTER)	+= dummy-counter.o
 obj-$(CONFIG_STM32_LPTIMER_CNT)	+= stm32-lptimer-cnt.o
drivers/iio/counter/dummy-counter.c new file +308 -0

308 lines not on this page · raw message

Signature · 1 line
2.15.1
#14 lore raw

PATCH v4 8/11 counter: Introduce the Quadrature Counter interface

In reply to William Breathitt Gray

This patch introduces the Quadrature Counter interface. The Quadrature Counter interface serves as an API to provide support for quadrature encoder counter devices. The Quadrature Counter interface is built on top of the Generic Counter interface.

A quadrature encoder counter device is a counter device that has a quadrature pair of signals associated with each count value. Signals may have a value of "low" or "high."

Signals may be represented by two possible states:

QUAD_COUNTER_SIGNAL_LOW: "low"
QUAD_COUNTER_SIGNAL_HIGH: "high"

With quadrature encoders, there types of encoding are typically used:
X1, X2, and X4; some quadrature encoders also offer a non-quadrature mode (typically pulse-direction encoding).

The Quadrature Counter interface provides four count function modes:

QUAD_COUNTER_FUNCTION_PULSE_DIRECTION: "pulse-direction" QUAD_COUNTER_FUNCTION_QUADRATURE_X1: "quadrature x1" QUAD_COUNTER_FUNCTION_QUADRATURE_X2: "quadrature x2" QUAD_COUNTER_FUNCTION_QUADRATURE_X4: "quadrature x4"

Since the Quadrature Counter interface utilizes the Generic Counter interface underneath, all the expected functionality of the Generic Counter interface such as sysfs attributes is exposed to userspace for end user consumption. The Quadrature Counter interface serves as a convenience API for supporting a common class of counter devices without the need to manually configure the more cumbersome Generic Counter interface for use.

In addition to the typical sysfs attributes of the Generic Counter interface, the Quadrature Counter interface provides "direction" attributes for each count value. These read-only attributes provide the current direction of their respective quadrature encoding stream.

To use the Quadrature Counter interface, first create an array of quad_counter_count structures to represent the desired counts and signals of the counter device; the signal_a member of a quad_counter_count structure should define the Channel A signal of the respective quadrature pair, and similarly the signal_b member should define Channel B. Next, allocate a quad_counter_device structure and populate it with the desired driver callbacks and the quad_counter_count array created earlier. Finally, register the counter by calling the quad_counter_register function. The quad_counter_unregister function may be used to unregistered a previously registered counter.

Memory-managed versions of quad_counter_register and quad_counter_unregister functions are provided by the devm_quad_counter_register and devm_quad_counter_unregister functions respectively.

---
 drivers/iio/counter/Kconfig        |   4 +-
 drivers/iio/counter/Makefile       |   1 +
 drivers/iio/counter/quad-counter.c | 774 +++++++++++++++++++++++++++++++++++++
 include/linux/iio/counter.h        | 191 +++++++++
 4 files changed, 969 insertions(+), 1 deletion(-)
 create mode 100644 drivers/iio/counter/quad-counter.c
drivers/iio/counter/Kconfig +3 -1
index 9d7dae137f9c..33fde25e5018 100644
@@ -10,7 +10,9 @@ menuconfig COUNTER
 	  rudimentary support for counters and serves as building blocks to
 	  create more complex counter interfaces. The Simple Counter API
 	  provides support for simple hardware counter devices that have a
-	  one-to-one mapping between their Signals and Counts.
+	  one-to-one mapping between their Signals and Counts. The Quadrature
+	  Counter API provides support for quadrature counter devices that have
+	  Signals arranged as quadrature pairs associated to Counts.
 
 if COUNTER
 
drivers/iio/counter/Makefile +1 -0
index febd2884b474..55f59e566d72 100644
@@ -6,6 +6,7 @@
 
 obj-$(CONFIG_COUNTER) += counter.o
 counter-$(CONFIG_COUNTER) += generic-counter.o
+counter-$(CONFIG_COUNTER) += quad-counter.o
 counter-$(CONFIG_COUNTER) += simple-counter.o
 
 obj-$(CONFIG_104_QUAD_8)	+= 104-quad-8.o
drivers/iio/counter/quad-counter.c new file +774 -0

774 lines not on this page · raw message

include/linux/iio/counter.h +191 -0

195 lines not on this page · raw message

Signature · 1 line
2.15.1
maintainer
#15 lore raw

Re: [PATCH v4 08/11] counter: Introduce the Quadrature Counter interface

Quoted 49 lines · On Thu, 14 Dec 2017 15:52:20 -0500 William Breathitt Gray…

This patch introduces the Quadrature Counter interface. The Quadrature Counter interface serves as an API to provide support for quadrature encoder counter devices. The Quadrature Counter interface is built on top of the Generic Counter interface.

A quadrature encoder counter device is a counter device that has a quadrature pair of signals associated with each count value. Signals may have a value of "low" or "high."

Signals may be represented by two possible states:

QUAD_COUNTER_SIGNAL_LOW: "low"
QUAD_COUNTER_SIGNAL_HIGH: "high"

With quadrature encoders, there types of encoding are typically used:
X1, X2, and X4; some quadrature encoders also offer a non-quadrature mode (typically pulse-direction encoding).

The Quadrature Counter interface provides four count function modes:

QUAD_COUNTER_FUNCTION_PULSE_DIRECTION: "pulse-direction" QUAD_COUNTER_FUNCTION_QUADRATURE_X1: "quadrature x1" QUAD_COUNTER_FUNCTION_QUADRATURE_X2: "quadrature x2" QUAD_COUNTER_FUNCTION_QUADRATURE_X4: "quadrature x4"

Since the Quadrature Counter interface utilizes the Generic Counter interface underneath, all the expected functionality of the Generic Counter interface such as sysfs attributes is exposed to userspace for end user consumption. The Quadrature Counter interface serves as a convenience API for supporting a common class of counter devices without the need to manually configure the more cumbersome Generic Counter interface for use.

In addition to the typical sysfs attributes of the Generic Counter interface, the Quadrature Counter interface provides "direction" attributes for each count value. These read-only attributes provide the current direction of their respective quadrature encoding stream.

To use the Quadrature Counter interface, first create an array of quad_counter_count structures to represent the desired counts and signals of the counter device; the signal_a member of a quad_counter_count structure should define the Channel A signal of the respective quadrature pair, and similarly the signal_b member should define Channel B. Next, allocate a quad_counter_device structure and populate it with the desired driver callbacks and the quad_counter_count array created earlier. Finally, register the counter by calling the quad_counter_register function. The quad_counter_unregister function may be used to unregistered a previously registered counter.

Quoted 6 lines

Memory-managed versions of quad_counter_register and quad_counter_unregister functions are provided by the devm_quad_counter_register and devm_quad_counter_unregister functions respectively.

Pretty much same few comments as for the simple counter so I haven't repeated here.

Jonathan

Quoted 1,015 lines
---
 drivers/iio/counter/Kconfig        |   4 +-
 drivers/iio/counter/Makefile       |   1 +
 drivers/iio/counter/quad-counter.c | 774 +++++++++++++++++++++++++++++++++++++
 include/linux/iio/counter.h        | 191 +++++++++
 4 files changed, 969 insertions(+), 1 deletion(-)
 create mode 100644 drivers/iio/counter/quad-counter.c
drivers/iio/counter/Kconfig +3 -1
index 9d7dae137f9c..33fde25e5018 100644
@@ -10,7 +10,9 @@ menuconfig COUNTER
 	  rudimentary support for counters and serves as building blocks to
 	  create more complex counter interfaces. The Simple Counter API
 	  provides support for simple hardware counter devices that have a
-	  one-to-one mapping between their Signals and Counts.
+	  one-to-one mapping between their Signals and Counts. The Quadrature
+	  Counter API provides support for quadrature counter devices that have
+	  Signals arranged as quadrature pairs associated to Counts.
 
 if COUNTER
 
drivers/iio/counter/Makefile +1 -0
index febd2884b474..55f59e566d72 100644
@@ -6,6 +6,7 @@
 
 obj-$(CONFIG_COUNTER) += counter.o
 counter-$(CONFIG_COUNTER) += generic-counter.o
+counter-$(CONFIG_COUNTER) += quad-counter.o
 counter-$(CONFIG_COUNTER) += simple-counter.o
 
 obj-$(CONFIG_104_QUAD_8)	+= 104-quad-8.o
drivers/iio/counter/quad-counter.c new file +774 -0
new file mode 100644
index 000000000000..74a738e4b515
@@ -0,0 +1,774 @@
+/*
+ * Quadrature Counter interface
+ * Copyright (C) 2017 William Breathitt Gray
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <linux/iio/counter.h>
+
+static const char *const quad_counter_signal_level_names[] = {
+	[QUAD_COUNTER_SIGNAL_LOW] = "low",
+	[QUAD_COUNTER_SIGNAL_HIGH] = "high"
+};
+
+static ssize_t quad_counter_signal_read(struct counter_device *counter_dev,
+	struct counter_signal *counter_sig, char *buf)
+{
+	struct quad_counter_device *const counter = counter_dev->priv;
+	struct quad_counter_signal *const signal = counter_sig->priv;
+	int err;
+	enum quad_counter_signal_level level;
+
+	err = counter->signal_read(counter, signal, &level);
+	if (err)
+		return err;
+
+	return scnprintf(buf, PAGE_SIZE, "%s\n",
+		quad_counter_signal_level_names[level]);
+}
+
+static ssize_t quad_counter_count_read(struct counter_device *counter_dev,
+	struct counter_count *counter_cnt, char *buf)
+{
+	struct quad_counter_device *const counter = counter_dev->priv;
+	struct quad_counter_count *const count = counter_cnt->priv;
+	int err;
+	long val;
+
+	err = counter->count_read(counter, count, &val);
+	if (err)
+		return err;
+
+	return scnprintf(buf, PAGE_SIZE, "%ld\n", val);
+}
+
+static ssize_t quad_counter_count_write(struct counter_device *counter_dev,
+	struct counter_count *counter_cnt, const char *buf, size_t len)
+{
+	struct quad_counter_device *const counter = counter_dev->priv;
+	struct quad_counter_count *const count = counter_cnt->priv;
+	int err;
+	long val;
+
+	err = kstrtol(buf, 0, &val);
+	if (err)
+		return err;
+
+	err = counter->count_write(counter, count, val);
+	if (err)
+		return err;
+
+	return len;
+}
+
+static int quad_counter_function_get(struct counter_device *counter_dev,
+	struct counter_count *counter_cnt, size_t *counter_func)
+{
+	int err;
+	struct quad_counter_device *const counter = counter_dev->priv;
+	struct quad_counter_count *const count = counter_cnt->priv;
+	enum quad_counter_function function;
+
+	err = counter->function_get(counter, count, &function);
+	if (err)
+		return err;
+
+	count->function = function;
+
+	*counter_func = function;
+
+	return 0;
+}
+
+static int quad_counter_function_set(struct counter_device *counter_dev,
+	struct counter_count *counter_cnt, size_t function)
+{
+	struct quad_counter_device *const counter = counter_dev->priv;
+	struct quad_counter_count *const count = counter_cnt->priv;
+	int err;
+
+	err = counter->function_set(counter, count, function);
+	if (err)
+		return err;
+
+	count->function = function;
+
+	return 0;
+}
+
+enum quad_counter_action {
+	QUAD_COUNTER_ACTION_NONE = 0,
+	QUAD_COUNTER_ACTION_RISING_EDGE,
+	QUAD_COUNTER_ACTION_FALLING_EDGE,
+	QUAD_COUNTER_ACTION_BOTH_EDGES
+};
+
+static int quad_counter_action_get(struct counter_device *counter_dev,
+	struct counter_count *counter_cnt, struct counter_synapse *counter_syn,
+	size_t *counter_act)
+{
+	int err;
+	struct quad_counter_device *const counter = counter_dev->priv;
+	struct quad_counter_count *const count = counter_cnt->priv;
+	enum quad_counter_function function;
+	enum quad_counter_direction dir;
+
+	err = counter->function_get(counter, count, &function);
+	if (err)
+		return err;
+
+	/* Default action mode */
+	*counter_act = QUAD_COUNTER_ACTION_NONE;
+
+	/* Determine action mode based on current count function mode */
+	switch (function) {
+	case QUAD_COUNTER_FUNCTION_PULSE_DIRECTION:
+		if (count->signal_a.id == counter_syn->signal->id)
+			*counter_act = QUAD_COUNTER_ACTION_RISING_EDGE;
+		break;
+	case QUAD_COUNTER_FUNCTION_QUADRATURE_X1:
+		if (count->signal_a.id == counter_syn->signal->id) {
+			err = counter->direction_get(counter, count, &dir);
+			if (err)
+				return err;
+
+			if (dir == QUAD_COUNTER_DIRECTION_FORWARD)
+				*counter_act = QUAD_COUNTER_ACTION_RISING_EDGE;
+			else
+				*counter_act = QUAD_COUNTER_ACTION_FALLING_EDGE;
+		}
+		break;
+	case QUAD_COUNTER_FUNCTION_QUADRATURE_X2:
+		if (count->signal_a.id == counter_syn->signal->id)
+			*counter_act = QUAD_COUNTER_ACTION_BOTH_EDGES;
+		break;
+	case QUAD_COUNTER_FUNCTION_QUADRATURE_X4:
+		*counter_act = QUAD_COUNTER_ACTION_BOTH_EDGES;
+		break;
+	}
+
+	return 0;
+}
+
+static ssize_t quad_counter_signal_ext_read(struct counter_device *dev,
+	struct counter_signal *signal, void *priv, char *buf)
+{
+	const struct quad_counter_signal_ext *const ext = priv;
+	struct quad_counter_device *const counter = dev->priv;
+	struct quad_counter_signal *const quad_signal = signal->priv;
+
+	return ext->read(counter, quad_signal, ext->priv, buf);
+}
+
+static ssize_t quad_counter_signal_ext_write(struct counter_device *dev,
+	struct counter_signal *signal, void *priv, const char *buf, size_t len)
+{
+	const struct quad_counter_signal_ext *const ext = priv;
+	struct quad_counter_device *const counter = dev->priv;
+	struct quad_counter_signal *const quad_signal = signal->priv;
+
+	return ext->write(counter, quad_signal, ext->priv, buf, len);
+}
+
+static int quad_counter_counter_signal_ext_register(
+	const struct quad_counter_signal *const quad_signal,
+	struct counter_signal *const signal)
+{
+	const struct quad_counter_signal_ext *const quad_ext = quad_signal->ext;
+	const size_t num_ext = quad_signal->num_ext;
+	struct counter_signal_ext *ext;
+	size_t i;
+
+	/* Exit early if no extensions */
+	if (!quad_ext || !num_ext)
+		return 0;
+
+	/* Allocate space for counter_signal_ext array */
+	ext = kmalloc_array(num_ext, sizeof(*ext), GFP_KERNEL);
+	if (!ext)
+		return -ENOMEM;
+
+	/* Register quad_counter_signal_ext via counter_signal_ext */
+	for (i = 0; i < num_ext; i++) {
+		ext[i].name = quad_ext[i].name;
+		ext[i].read = (quad_ext[i].read) ?
+			quad_counter_signal_ext_read : NULL;
+		ext[i].write = (quad_ext[i].write) ?
+			quad_counter_signal_ext_write : NULL;
+		ext[i].priv = quad_ext + i;
+	}
+
+	/* Register Counter Signal extensions */
+	signal->ext = ext;
+	signal->num_ext = num_ext;
+
+	return 0;
+}
+
+static int quad_counter_counter_signals_register(
+	const struct quad_counter_device *const counter)
+{
+	struct counter_signal *signals;
+	const size_t num_counts = counter->num_counts;
+	const size_t num_signals = 2 * num_counts;
+	size_t i;
+	struct counter_signal *signal;
+	struct quad_counter_signal *quad_signal;
+	struct quad_counter_count *const counts = counter->counts;
+	int err;
+	struct counter_device *const counter_dev = counter->counter_dev;
+
+	/* Allocate space for signals array */
+	signals = kcalloc(num_signals, sizeof(*signals), GFP_KERNEL);
+	if (!signals)
+		return -ENOMEM;
+
+	/* Configure Signals */
+	for (i = 0; i < num_signals; i++) {
+		signal = signals + i;
+		if (i % 2)
+			quad_signal = &counts[i / 2].signal_b;
+		else
+			quad_signal = &counts[i / 2].signal_a;
+
+		signal->id = quad_signal->id;
+		signal->name = quad_signal->name;
+		signal->priv = quad_signal;
+
+		/* Register Counter Signal extensions */
+		err = quad_counter_counter_signal_ext_register(quad_signal,
+			signal);
+		if (err)
+			goto err_free_signals;
+	}
+
+	/* Register Signals to Counter device container */
+	counter_dev->signals = signals;
+	counter_dev->num_signals = num_signals;
+
+	return 0;
+
+err_free_signals:
+	while (i--)
+		kfree(signals[i].ext);
+	kfree(signals);
+	return err;
+}
+
+static const char *const quad_counter_function_names[] = {
+	[QUAD_COUNTER_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
+	[QUAD_COUNTER_FUNCTION_QUADRATURE_X1] = "quadrature x1",
+	[QUAD_COUNTER_FUNCTION_QUADRATURE_X2] = "quadrature x2",
+	[QUAD_COUNTER_FUNCTION_QUADRATURE_X4] = "quadrature x4"
+};
+
+static const char *const quad_counter_action_names[] = {
+	[QUAD_COUNTER_ACTION_NONE] = "none",
+	[QUAD_COUNTER_ACTION_RISING_EDGE] = "rising edge",
+	[QUAD_COUNTER_ACTION_FALLING_EDGE] = "falling edge",
+	[QUAD_COUNTER_ACTION_BOTH_EDGES] = "both edges"
+};
+
+static int quad_counter_counter_synapses_register(
+	struct counter_signal *const signals, struct counter_count *const count)
+{
+	struct counter_synapse *synapses;
+	const size_t num_synapses = 2;
+	size_t i;
+
+	/* Allocate space for Counter Synapses */
+	synapses = kcalloc(num_synapses, sizeof(*synapses), GFP_KERNEL);
+	if (!synapses)
+		return -ENOMEM;
+
+	/* Configure Synapses */
+	for (i = 0; i < num_synapses; i++) {
+		synapses[i].signal = signals + i;
+		synapses[i].actions = quad_counter_action_names;
+		synapses[i].num_actions = ARRAY_SIZE(quad_counter_action_names);
+	}
+
+	/* Register Counter Synapses */
+	count->synapses = synapses;
+	count->num_synapses = num_synapses;
+
+	return 0;
+}
+
+static const char *const quad_counter_direction_names[] = {
+	[QUAD_COUNTER_DIRECTION_FORWARD] = "forward",
+	[QUAD_COUNTER_DIRECTION_BACKWARD] = "backward"
+};
+
+static ssize_t quad_counter_direction_read(struct counter_device *dev,
+	struct counter_count *count, void *priv, char *buf)
+{
+	struct quad_counter_device *const counter = dev->priv;
+	struct quad_counter_count *const quad_count = count->priv;
+	int err;
+	enum quad_counter_direction direction;
+
+	err = counter->direction_get(counter, quad_count, &direction);
+	if (err)
+		return err;
+
+	return scnprintf(buf, PAGE_SIZE, "%s\n",
+		quad_counter_direction_names[direction]);
+}
+
+static ssize_t quad_counter_count_ext_read(struct counter_device *dev,
+	struct counter_count *count, void *priv, char *buf)
+{
+	const struct quad_counter_count_ext *const ext = priv;
+	struct quad_counter_device *const counter = dev->priv;
+	struct quad_counter_count *const quad_count = count->priv;
+
+	return ext->read(counter, quad_count, ext->priv, buf);
+}
+
+static ssize_t quad_counter_count_ext_write(struct counter_device *dev,
+	struct counter_count *count, void *priv, const char *buf, size_t len)
+{
+	const struct quad_counter_count_ext *const ext = priv;
+	struct quad_counter_device *const counter = dev->priv;
+	struct quad_counter_count *const quad_count = count->priv;
+
+	return ext->write(counter, quad_count, ext->priv, buf, len);
+}
+
+static int quad_counter_counter_count_ext_register(
+	const struct quad_counter_device *const counter,
+	const struct quad_counter_count *const quad_count,
+	struct counter_count *const count)
+{
+	size_t num_ext = 0;
+	const struct quad_counter_count_ext *const quad_ext = quad_count->ext;
+	const size_t quad_num_ext = quad_count->num_ext;
+	struct counter_count_ext *ext;
+	size_t ext_i = 0;
+	size_t i;
+
+	/* Count number of extensions */
+	if (counter->direction_get)
+		num_ext++;
+	if (quad_ext)
+		num_ext += quad_num_ext;
+
+	/* Return early if no extensions */
+	if (!num_ext)
+		return 0;
+
+	/* Allocate space for Counter Count extensions array */
+	ext = kcalloc(num_ext, sizeof(*ext), GFP_KERNEL);
+	if (!ext)
+		return -ENOMEM;
+
+	/* Register direction extension */
+	if (counter->direction_get) {
+		ext[ext_i].name = "direction";
+		ext[ext_i].read = quad_counter_direction_read;
+
+		ext_i++;
+	}
+
+	/* Register driver Quadrature Counter Count extensions */
+	for (i = 0; i < quad_num_ext; i++) {
+		ext[ext_i + i].name = quad_ext[i].name;
+		ext[ext_i + i].read = (quad_ext[i].read) ?
+			quad_counter_count_ext_read : NULL;
+		ext[ext_i + i].write = (quad_ext[i].write) ?
+			quad_counter_count_ext_write : NULL;
+		ext[ext_i + i].priv = quad_ext + i;
+	}
+	ext_i += quad_num_ext;
+
+	/* Register Counter Count extensions */
+	count->ext = ext;
+	count->num_ext = num_ext;
+
+	return 0;
+}
+
+static void quad_counter_counter_synapses_unregister(
+	const struct counter_count *const count)
+{
+	kfree(count->synapses);
+}
+
+static int quad_counter_counter_count_init(struct counter_count *const count,
+	struct quad_counter_count *const quad_count,
+	struct counter_signal *const signals,
+	const struct quad_counter_device *const counter)
+{
+	int err;
+
+	count->id = quad_count->id;
+	count->name = quad_count->name;
+	count->functions = quad_counter_function_names;
+	count->num_functions = ARRAY_SIZE(quad_counter_function_names);
+	count->priv = quad_count;
+
+	/* Register Counter Synapses */
+	err = quad_counter_counter_synapses_register(signals, count);
+	if (err)
+		return -ENOMEM;
+
+	/* Register Quadrature Counter Count extensions */
+	err = quad_counter_counter_count_ext_register(counter, quad_count,
+		count);
+	if (err)
+		goto err_unregister_synapses;
+
+	return 0;
+
+err_unregister_synapses:
+	quad_counter_counter_synapses_unregister(count);
+	return err;
+}
+
+static void quad_counter_counter_count_ext_unregister(
+	const struct counter_count *const count)
+{
+	kfree(count->ext);
+}
+
+static void quad_counter_counter_count_free(
+	const struct counter_count *const count)
+{
+	quad_counter_counter_count_ext_unregister(count);
+	quad_counter_counter_synapses_unregister(count);
+}
+
+static int quad_counter_counter_counts_register(
+	const struct quad_counter_device *const counter)
+{
+	struct counter_device *const counter_dev = counter->counter_dev;
+	struct counter_count *counts;
+	const size_t num_counts = counter->num_counts;
+	size_t i;
+	struct quad_counter_count *const quad_counts = counter->counts;
+	struct counter_signal *const signals = counter_dev->signals;
+	int err;
+
+	/* Allocate space for counts array */
+	counts = kcalloc(num_counts, sizeof(*counts), GFP_KERNEL);
+	if (!counts)
+		return -ENOMEM;
+
+	/* Initialize Counts */
+	for (i = 0; i < num_counts; i++) {
+		err = quad_counter_counter_count_init(counts + i,
+			quad_counts + i, signals + 2 * i, counter);
+		if (err)
+			goto err_free_counts;
+	}
+
+	/* Register Counts to Counter device container */
+	counter_dev->counts = counts;
+	counter_dev->num_counts = num_counts;
+
+	return 0;
+
+err_free_counts:
+	while (i--)
+		quad_counter_counter_count_free(counts + i);
+	kfree(counts);
+	return err;
+}
+
+static void quad_counter_counter_signals_unregister(
+	const struct counter_device *const counter_dev)
+{
+	const struct counter_signal *const signals = counter_dev->signals;
+	size_t num_signals = counter_dev->num_signals;
+
+	while (num_signals--)
+		kfree(signals[num_signals].ext);
+	kfree(signals);
+}
+
+static int quad_counter_counts_register(
+	struct quad_counter_device *const counter)
+{
+	const struct quad_counter_count *const quad_counts = counter->counts;
+	const size_t num_counts = counter->num_counts;
+	int err;
+
+	/* At least one Count must be defined */
+	if (!quad_counts || !num_counts) {
+		pr_err("quad-counter: Quadrature Counter Counts undefined\n");
+		return -EINVAL;
+	}
+
+	/* Allocate Counter Signals */
+	err = quad_counter_counter_signals_register(counter);
+	if (err)
+		return err;
+
+	/* Allocate Counter Counts */
+	err = quad_counter_counter_counts_register(counter);
+	if (err)
+		goto err_unregister_signals;
+
+	return 0;
+
+err_unregister_signals:
+	quad_counter_counter_signals_unregister(counter->counter_dev);
+	return err;
+}
+
+static ssize_t quad_counter_device_ext_read(struct counter_device *dev,
+	void *priv, char *buf)
+{
+	const struct quad_counter_device_ext *const ext = priv;
+	struct quad_counter_device *const counter = dev->priv;
+
+	return ext->read(counter, ext->priv, buf);
+}
+
+static ssize_t quad_counter_device_ext_write(struct counter_device *dev,
+	void *priv, const char *buf, size_t len)
+{
+	const struct quad_counter_device_ext *const ext = priv;
+	struct quad_counter_device *const counter = dev->priv;
+
+	return ext->write(counter, ext->priv, buf, len);
+}
+
+static int quad_counter_device_ext_register(
+	struct quad_counter_device *const counter)
+{
+	const struct quad_counter_device_ext *const quad_ext = counter->ext;
+	const size_t num_ext = counter->num_ext;
+	struct counter_device_ext *ext;
+	size_t i;
+	struct counter_device *const counter_dev = counter->counter_dev;
+
+	/* Return early if no extensions */
+	if (!quad_ext || !num_ext)
+		return 0;
+
+	/* Allocate space for counter_device_ext array */
+	ext = kmalloc_array(num_ext, sizeof(*ext), GFP_KERNEL);
+	if (!ext)
+		return -ENOMEM;
+
+	/* Register quad_counter_device_ext via counter_device_ext */
+	for (i = 0; i < num_ext; i++) {
+		ext[i].name = quad_ext[i].name;
+		ext[i].read = (quad_ext[i].read) ?
+			quad_counter_device_ext_read : NULL;
+		ext[i].write = (quad_ext[i].write) ?
+			quad_counter_device_ext_write : NULL;
+		ext[i].priv = quad_ext + i;
+	}
+
+	/* Register Counter device extensions */
+	counter_dev->ext = ext;
+	counter_dev->num_ext = num_ext;
+
+	return 0;
+}
+
+static void quad_counter_counter_counts_unregister(
+	const struct counter_device *const counter_dev)
+{
+	const struct counter_count *const counts = counter_dev->counts;
+	size_t num_counts = counter_dev->num_counts;
+
+	while (num_counts--)
+		quad_counter_counter_count_free(counts + num_counts);
+	kfree(counts);
+}
+
+static void quad_counter_counts_unregister(
+	const struct quad_counter_device *const counter)
+{
+	const struct counter_device *const counter_dev = counter->counter_dev;
+
+	quad_counter_counter_counts_unregister(counter_dev);
+	quad_counter_counter_signals_unregister(counter_dev);
+}
+
+/**
+ * quad_counter_register - register Quadrature Counter to the system
+ * @counter: pointer to Quadrature Counter to register
+ *
+ * This function registers a Quadrature Counter to the system. A sysfs "counter"
+ * directory will be created and populated with sysfs attributes correlating
+ * with the Quadrature Counter Signals, Synapses, and Counts respectively.
+ */
+int quad_counter_register(struct quad_counter_device *const counter)
+{
+	struct counter_device *counter_dev;
+	int err;
+
+	if (!counter)
+		return -EINVAL;
+
+	/* Allocate internal Counter container */
+	counter_dev = kzalloc(sizeof(*counter_dev), GFP_KERNEL);
+	if (!counter)
+		return -ENOMEM;
+	counter->counter_dev = counter_dev;
+
+	/* Configure internal Counter */
+	counter_dev->name = counter->name;
+	counter_dev->parent = counter->parent;
+	counter_dev->signal_read = (counter->signal_read) ?
+		quad_counter_signal_read : NULL;
+	counter_dev->count_read = (counter->count_read) ?
+		quad_counter_count_read : NULL;
+	counter_dev->count_write = (counter->count_write) ?
+		quad_counter_count_write : NULL;
+	counter_dev->function_get = (counter->function_get) ?
+		quad_counter_function_get : NULL;
+	counter_dev->function_set = (counter->function_set) ?
+		quad_counter_function_set : NULL;
+	counter_dev->action_get = (counter->function_get &&
+		counter->direction_get) ? quad_counter_action_get : NULL;
+	counter_dev->priv = counter;
+
+	/* Register Quadrature Counter Counts */
+	err = quad_counter_counts_register(counter);
+	if (err)
+		goto err_free_counter_dev;
+
+	/* Register Quadrature Counter device extension attributes */
+	err = quad_counter_device_ext_register(counter);
+	if (err)
+		goto err_unregister_counts;
+
+	/* Register internal Counter to the system */
+	err = counter_register(counter_dev);
+	if (err)
+		goto err_free_ext;
+
+	return 0;
+
+err_free_ext:
+	kfree(counter_dev->ext);
+err_unregister_counts:
+	quad_counter_counts_unregister(counter);
+err_free_counter_dev:
+	kfree(counter_dev);
+	return err;
+}
+EXPORT_SYMBOL(quad_counter_register);
+
+/**
+ * quad_counter_unregister - unregister Quadrature Counter from the system
+ * @counter: pointer to Quadrature Counter to unregister
+ *
+ * The Quadrature Counter is unregistered from the system; all allocated memory
+ * is freed.
+ */
+void quad_counter_unregister(struct quad_counter_device *const counter)
+{
+	struct counter_device *counter_dev;
+
+	if (!counter)
+		return;
+
+	counter_dev = counter->counter_dev;
+
+	counter_unregister(counter_dev);
+
+	kfree(counter_dev->ext);
+	quad_counter_counts_unregister(counter);
+	kfree(counter_dev);
+}
+EXPORT_SYMBOL(quad_counter_unregister);
+
+static void devm_quad_counter_unreg(struct device *dev, void *res)
+{
+	quad_counter_unregister(*(struct quad_counter_device **)res);
+}
+
+/**
+ * devm_quad_counter_register - Resource-managed quad_counter_register
+ * @dev: device to allocate quad_counter_device for
+ * @counter: pointer to Quadrature Counter to register
+ *
+ * Managed quad_counter_register. The Quadrature Counter registered with this
+ * function is automatically unregistered on driver detach. This function calls
+ * quad_counter_register internally. Refer to that function for more
+ * information.
+ *
+ * If an Quadrature Counter registered with this function needs to be
+ * unregistered separately, devm_quad_counter_unregister must be used.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int devm_quad_counter_register(struct device *dev,
+	struct quad_counter_device *const counter)
+{
+	struct quad_counter_device **ptr;
+	int ret;
+
+	ptr = devres_alloc(devm_quad_counter_unreg, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+
+	ret = quad_counter_register(counter);
+	if (!ret) {
+		*ptr = counter;
+		devres_add(dev, ptr);
+	} else
+		devres_free(ptr);
+
+	return ret;
+}
+EXPORT_SYMBOL(devm_quad_counter_register);
+
+static int devm_quad_counter_match(struct device *dev, void *res, void *data)
+{
+	struct quad_counter_device **r = res;
+
+	if (!r || !*r) {
+		WARN_ON(!r || !*r);
+		return 0;
+	}
+
+	return *r == data;
+}
+
+/**
+ * devm_quad_counter_unregister - Resource-managed quad_counter_unregister
+ * @dev: device this quad_counter_device belongs to
+ * @counter: the Quadrature Counter associated with the device
+ *
+ * Unregister Quadrature Counter registered with devm_quad_counter_register.
+ */
+void devm_quad_counter_unregister(struct device *dev,
+	struct quad_counter_device *const counter)
+{
+	int rc;
+
+	rc = devres_release(dev, devm_quad_counter_unreg,
+		devm_quad_counter_match, counter);
+	WARN_ON(rc);
+}
+EXPORT_SYMBOL(devm_quad_counter_unregister);
+
+MODULE_AUTHOR("William Breathitt Gray <[email protected]>");
+MODULE_DESCRIPTION("Quadrature Counter interface");
+MODULE_LICENSE("GPL v2");
include/linux/iio/counter.h +191 -0
index 0967ea2a9bef..a6f0f9130377 100644
@@ -435,4 +435,195 @@ extern int devm_simple_counter_register(struct device *dev,
 extern void devm_simple_counter_unregister(struct device *dev,
 	struct simple_counter_device *const counter);
 
+struct quad_counter_device;
+struct quad_counter_signal;
+
+/**
+ * struct quad_counter_signal_ext - Quadrature Counter Signal extension
+ * @name:	[DRIVER] attribute name
+ * @read:	[DRIVER] read callback for this attribute; may be NULL
+ * @write:	[DRIVER] write callback for this attribute; may be NULL
+ * @priv:	[DRIVER] data private to the driver
+ */
+struct quad_counter_signal_ext {
+	const char	*name;
+	ssize_t		(*read)(struct quad_counter_device *counter,
+				struct quad_counter_signal *signal, void *priv,
+				char *buf);
+	ssize_t		(*write)(struct quad_counter_device *counter,
+				struct quad_counter_signal *signal, void *priv,
+				const char *buf, size_t len);
+	void		*priv;
+};
+
+/**
+ * struct quad_counter_signal - Quadrature Counter Signal node
+ * @id:		[DRIVER] unique ID used to identify signal
+ * @name:	[DRIVER] device-specific signal name
+ * @ext:	[DRIVER] optional array of Quadrature Counter Signal extensions
+ * @num_ext:	[DRIVER] number of Quadrature Counter Signal extensions
+ *		specified in @ext
+ * @priv:	[DRIVER] optional private data supplied by driver
+ */
+struct quad_counter_signal {
+	int		id;
+	const char	*name;
+
+	const struct quad_counter_signal_ext	*ext;
+	size_t					num_ext;
+
+	void	*priv;
+};
+
+enum quad_counter_signal_level {
+	QUAD_COUNTER_SIGNAL_LOW = 0,
+	QUAD_COUNTER_SIGNAL_HIGH
+};
+
+struct quad_counter_count;
+
+enum quad_counter_function {
+	QUAD_COUNTER_FUNCTION_PULSE_DIRECTION = 0,
+	QUAD_COUNTER_FUNCTION_QUADRATURE_X1,
+	QUAD_COUNTER_FUNCTION_QUADRATURE_X2,
+	QUAD_COUNTER_FUNCTION_QUADRATURE_X4
+};
+
+enum quad_counter_direction {
+	QUAD_COUNTER_DIRECTION_FORWARD = 0,
+	QUAD_COUNTER_DIRECTION_BACKWARD
+};
+
+/**
+ * struct quad_counter_count_ext - Quadrature Counter Count extension
+ * @name:	[DRIVER] attribute name
+ * @read:	[DRIVER] read callback for this attribute; may be NULL
+ * @write:	[DRIVER] write callback for this attribute; may be NULL
+ * @priv:	[DRIVER] data private to the driver
+ */
+struct quad_counter_count_ext {
+	const char	*name;
+	ssize_t		(*read)(struct quad_counter_device *counter,
+				struct quad_counter_count *count, void *priv,
+				char *buf);
+	ssize_t		(*write)(struct quad_counter_device *counter,
+				struct quad_counter_count *count, void *priv,
+				const char *buf, size_t len);
+	void		*priv;
+};
+
+/**
+ * struct quad_counter_count - Quadrature Counter Count node
+ * @id:		[DRIVER] unique ID used to identify Count
+ * @name:	[DRIVER] device-specific Count name
+ * @function:	[DRIVER] current function mode
+ * @direction:	[DRIVER] current direction state
+ * @signal_a:	[DRIVER] associated quadrature A signal
+ * @signal_b:	[DRIVER] associated quadrature B signal
+ * @ext:	[DRIVER] optional array of Quadrature Counter Count extensions
+ * @num_ext:	[DRIVER] number of Quadrature Counter Count extensions specified
+ *		in @ext
+ * @priv:	[DRIVER] optional private data supplied by driver
+ */
+struct quad_counter_count {
+	int				id;
+	const char			*name;
+	enum quad_counter_function	function;
+	enum quad_counter_direction	direction;
+
+	struct quad_counter_signal	signal_a;
+	struct quad_counter_signal	signal_b;
+
+	const struct quad_counter_count_ext	*ext;
+	size_t					num_ext;
+
+	void	*priv;
+};
+
+/**
+ * struct quad_counter_device_ext - Quadrature Counter device extension
+ * @name:	[DRIVER] attribute name
+ * @read:	[DRIVER] read callback for this attribute; may be NULL
+ * @write:	[DRIVER] write callback for this attribute; may be NULL
+ * @priv:	[DRIVER] data private to the driver
+ */
+struct quad_counter_device_ext {
+	const char	*name;
+	ssize_t		(*read)(struct quad_counter_device *counter, void *priv,
+				char *buf);
+	ssize_t		(*write)(struct quad_counter_device *counter,
+				void *priv, const char *buf, size_t len);
+	void		*priv;
+};
+
+/**
+ * struct quad_counter_device - Quadrature Counter data structure
+ * @name:		[DRIVER] name of the device
+ * @parent:		[DRIVER] optional parent device providing the counters
+ * @counter_dev:	[INTERN] internal Counter container
+ * @signal_read:	[DRIVER] read callback for Signal attribute; may be
+ *			NULL. Returns 0 on success and negative error code on
+ *			error. The respective Signal's returned	level should be
+ *			passed back via the level parameter.
+ * @count_read:		[DRIVER] read callback for Count attribute; may be NULL.
+ *			Returns 0 on success and negative error code on error.
+ *			The respective Count's returned value should be passed
+ *			back via the val parameter.
+ * @count_write:	[DRIVER] write callback for Count attribute; may be NULL
+ * @function_get:	[DRIVER] function to get the current count function
+ *			mode. Returns 0 on success and negative error code on
+ *			error. The respective Count's returned function mode
+ *			should be passed back via the function parameter.
+ * @function_set:	[DRIVER] function to set the count function mode
+ * @direction_get:	[DRIVER] function to get the current direction. Returns
+ *			0 on success and negative error code on	error. The
+ *			respective Count's returned direction should be passed
+ *			back via the direction parameter.
+ * @counts:		[DRIVER] array of Quadrature Counter Counts
+ * @num_counts:		[DRIVER] number of Quadrature Counter Counts specified
+ *			in @counts
+ * @ext:		[DRIVER] optional array of Quadrature Counter device
+ *			extensions
+ * @num_ext:		[DRIVER] number of Quadrature Counter device extensions
+ *			specified in @ext
+ * @priv:		[DRIVER] optional private data supplied by driver
+ */
+struct quad_counter_device {
+	const char		*name;
+	struct device		*parent;
+	struct counter_device	*counter_dev;
+
+	int	(*signal_read)(struct quad_counter_device *counter,
+			struct quad_counter_signal *signal,
+			enum quad_counter_signal_level *level);
+	int	(*count_read)(struct quad_counter_device *counter,
+			struct quad_counter_count *count, long *val);
+	int	(*count_write)(struct quad_counter_device *counter,
+			struct quad_counter_count *count, long val);
+	int	(*function_get)(struct quad_counter_device *counter,
+			struct quad_counter_count *count,
+			enum quad_counter_function *function);
+	int	(*function_set)(struct quad_counter_device *counter,
+			struct quad_counter_count *count,
+			enum quad_counter_function function);
+	int	(*direction_get)(struct quad_counter_device *counter,
+			struct quad_counter_count *count,
+			enum quad_counter_direction *direction);
+
+	struct quad_counter_count	*counts;
+	size_t				num_counts;
+
+	const struct quad_counter_device_ext	*ext;
+	size_t					num_ext;
+
+	void	*priv;
+};
+
+extern int quad_counter_register(struct quad_counter_device *const counter);
+extern void quad_counter_unregister(struct quad_counter_device *const counter);
+extern int devm_quad_counter_register(struct device *dev,
+	struct quad_counter_device *const counter);
+extern void devm_quad_counter_unregister(struct device *dev,
+	struct quad_counter_device *const counter);
+
 #endif /* _COUNTER_H_ */
#16 lore raw

PATCH v4 9/11 counter: Documentation: Add Quadrature Counter sysfs documentation

In reply to William Breathitt Gray

This patch adds standard documentation for the userspace sysfs attributes of the Quadrature Counter interface.

---
 .../ABI/testing/sysfs-bus-counter-quadrature-sysfs | 76 ++++++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-quadrature-sysfs
Documentation/ABI/testing/sysfs-bus-counter-quadrature-sysfs new file +76 -0
new file mode 100644
index 000000000000..69d1a3e4a1a5
@@ -0,0 +1,76 @@
+What:		/sys/bus/counter/devices/counterX/countY
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Count data of Count Y. This is a signed integer value that
+		represents the position. Typically, this is determined by
+		hardware evaluation of the quadrature encoding input signals.
+
+What:		/sys/bus/counter/devices/counterX/countY_direction
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Count direction of Count Y. Typically, this is determined by
+		hardware evaluation of the quadrature encoding input signals.
+		Two count directions are available: forward and backward.
+
+What:		/sys/bus/counter/devices/counterX/countY_function
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Count function mode of Count Y. Count function evaluation is
+		triggered by conditions specified by the countY_signalZ_action
+		attributes. Four count function modes are available:
+		pulse-direction, quadrature x1, quadrature x2, quadrature x4.
+
+		Pulse-Direction:
+			Rising edges on quadrature pair signal A updates the
+			respective count. The input level of quadrature pair
+			signal B determines direction.
+
+		Quadrature x1:
+			If direction is forward, rising edges on quadrature pair
+			signal A updates the respective count; if the direction
+			is backward, falling edges on quadrature pair signal A
+			updates the respective count. Quadrature encoding
+			determines the direction.
+
+		Quadrature x2:
+			Any state transition on quadrature pair signal A updates
+			the respective count. Quadrature encoding determines the
+			direction.
+
+		Quadrature x4:
+			Any state transition on either quadrature pair signals
+			updates	the respective count. Quadrature encoding
+			determines the direction.
+
+What:		/sys/bus/counter/devices/counterX/countY_signalZ_action
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Action mode of Count Y for Signal Z. This attribute indicates
+		the condition of Signal Z that triggers the count function
+		evaluation for Count Y. Four action modes are available: none,
+		rising edge, falling edge, and both edges.
+
+		None:
+			Signal does not trigger the count function. In
+			Pulse-Direction count function mode, this Signal is
+			evaluated as Direction.
+
+		Rising Edge:
+			Low state transitions to High state.
+
+		Falling Edge:
+			High state transitions to Low state.
+
+		Both Edges:
+			Any state transition.
+
+What:		/sys/bus/counter/devices/counterX/signalY
+KernelVersion:	4.16
+Contact:	[email protected]
+Description:
+		Signal data of Signal Y. This is the respective input level
+		represented by two available states: low and high.
Signature · 1 line
2.15.1
#17 lore raw

PATCH v4 10/11 docs: Add Quadrature Counter interface documentation

In reply to William Breathitt Gray

This patch adds high-level documentation about the Quadrature Counter interface.

---
 Documentation/driver-api/iio/index.rst        |   1 +
 Documentation/driver-api/iio/quad-counter.rst | 444 ++++++++++++++++++++++++++
 2 files changed, 445 insertions(+)
 create mode 100644 Documentation/driver-api/iio/quad-counter.rst
Documentation/driver-api/iio/index.rst +1 -0
index 60e17f16cfb8..db1e2d7e7b87 100644
@@ -17,3 +17,4 @@ Contents:
    triggered-buffers
    generic-counter
    simple-counter
+   quad-counter
Documentation/driver-api/iio/quad-counter.rst new file +444 -0

444 lines not on this page · raw message

Signature · 1 line
2.15.1
#18 lore raw

PATCH v4 11/11 counter: 104-quad-8: Add Quadrature Counter interface support

In reply to William Breathitt Gray

This patch adds support for the Quadrature Counter interface to the 104-QUAD-8 driver. The existing 104-QUAD-8 device interface should not be affected by this patch; all changes are intended as supplemental additions as perceived by the user.

Quadrature Counter Counts are created for the eight quadrature channel counts, and their respective quadrature A and B signals are associated via the respective quad_counter_count structure.

The new Quadrature Counter interface sysfs attributes are intended to expose the same functionality and data available via the existing 104-QUAD-8 IIO device interface; the Quadrature Counter interface serves to provide the respective functionality and data in a standard way expected of quadrature counter devices.

---
 drivers/iio/counter/104-quad-8.c | 257 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 247 insertions(+), 10 deletions(-)
drivers/iio/counter/104-quad-8.c +247 -10
index b56985078d8c..3a82503525f5 100644
@@ -16,6 +16,7 @@
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
+#include <linux/iio/counter.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/types.h>
 #include <linux/io.h>
@@ -24,6 +25,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/string.h>
 #include <linux/types.h>
 
 #define QUAD8_EXTENT 32
@@ -37,6 +39,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
 
 /**
  * struct quad8_iio - IIO device private data structure
+ * @counter:		instance of the quad_counter_device
  * @preset:		array of preset values
  * @count_mode:		array of count mode configurations
  * @quadrature_mode:	array of quadrature mode configurations
@@ -48,6 +51,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
  * @base:		base port address of the IIO device
  */
 struct quad8_iio {
+	struct quad_counter_device counter;
 	unsigned int preset[QUAD8_NUM_COUNTERS];
 	unsigned int count_mode[QUAD8_NUM_COUNTERS];
 	unsigned int quadrature_mode[QUAD8_NUM_COUNTERS];
@@ -527,24 +531,233 @@ static const struct iio_chan_spec quad8_channels[] = {
 	QUAD8_COUNT_CHAN(7), QUAD8_INDEX_CHAN(7)
 };
 
+static int quad8_signal_read(struct quad_counter_device *counter,
+	struct quad_counter_signal *signal,
+	enum quad_counter_signal_level *level)
+{
+	const struct quad8_iio *const priv = counter->priv;
+	unsigned int state;
+
+	/* Only Index signal levels can be read */
+	if (signal->id < 16)
+		return -EINVAL;
+
+	state = inb(priv->base + 0x16) & BIT(signal->id - 16);
+
+	*level = (state) ? QUAD_COUNTER_SIGNAL_HIGH : QUAD_COUNTER_SIGNAL_LOW;
+
+	return 0;
+}
+
+static int quad8_count_read(struct quad_counter_device *counter,
+	struct quad_counter_count *count, long *val)
+{
+	const struct quad8_iio *const priv = counter->priv;
+	const int base_offset = priv->base + 2 * count->id;
+	unsigned int flags;
+	unsigned int borrow;
+	unsigned int carry;
+	int i;
+
+	flags = inb(base_offset + 1);
+	borrow = flags & BIT(0);
+	carry = !!(flags & BIT(1));
+
+	/* Borrow XOR Carry effectively doubles count range */
+	*val = (borrow ^ carry) << 24;
+
+	/* Reset Byte Pointer; transfer Counter to Output Latch */
+	outb(0x11, base_offset + 1);
+
+	for (i = 0; i < 3; i++)
+		*val |= (long)inb(base_offset) << (8 * i);
+
+	return 0;
+}
+
+static int quad8_count_write(struct quad_counter_device *counter,
+	struct quad_counter_count *count, long val)
+{
+	const struct quad8_iio *const priv = counter->priv;
+	const int base_offset = priv->base + 2 * count->id;
+	int i;
+
+	/* Only 24-bit values are supported */
+	if (val > 0xFFFFFF)
+		return -EINVAL;
+
+	/* Reset Byte Pointer */
+	outb(0x01, base_offset + 1);
+
+	/* Counter can only be set via Preset Register */
+	for (i = 0; i < 3; i++)
+		outb(val >> (8 * i), base_offset);
+
+	/* Transfer Preset Register to Counter */
+	outb(0x08, base_offset + 1);
+
+	/* Reset Byte Pointer */
+	outb(0x01, base_offset + 1);
+
+	/* Set Preset Register back to original value */
+	val = priv->preset[count->id];
+	for (i = 0; i < 3; i++)
+		outb(val >> (8 * i), base_offset);
+
+	/* Reset Borrow, Carry, Compare, and Sign flags */
+	outb(0x02, base_offset + 1);
+	/* Reset Error flag */
+	outb(0x06, base_offset + 1);
+
+	return 0;
+}
+
+static int quad8_function_get(struct quad_counter_device *counter,
+	struct quad_counter_count *count,
+	enum quad_counter_function *function)
+{
+	const struct quad8_iio *const priv = counter->priv;
+	const int id = count->id;
+	const unsigned int quadrature_mode = priv->quadrature_mode[id];
+	const unsigned int scale = priv->quadrature_scale[id];
+
+	if (quadrature_mode)
+		switch (scale) {
+		case 0:
+			*function = QUAD_COUNTER_FUNCTION_QUADRATURE_X1;
+			break;
+		case 1:
+			*function = QUAD_COUNTER_FUNCTION_QUADRATURE_X2;
+			break;
+		case 2:
+			*function = QUAD_COUNTER_FUNCTION_QUADRATURE_X4;
+			break;
+		}
+	else
+		*function = QUAD_COUNTER_FUNCTION_PULSE_DIRECTION;
+
+	return 0;
+}
+
+static int quad8_function_set(struct quad_counter_device *counter,
+	struct quad_counter_count *count, enum quad_counter_function function)
+{
+	struct quad8_iio *const priv = counter->priv;
+	const int id = count->id;
+	unsigned int *const quadrature_mode = priv->quadrature_mode + id;
+	unsigned int *const scale = priv->quadrature_scale + id;
+	unsigned int mode_cfg = priv->count_mode[id] << 1;
+	unsigned int *const synchronous_mode = priv->synchronous_mode + id;
+	const unsigned int idr_cfg = priv->index_polarity[id] << 1;
+	const int base_offset = priv->base + 2 * id + 1;
+
+	if (function == QUAD_COUNTER_FUNCTION_PULSE_DIRECTION) {
+		*quadrature_mode = 0;
+
+		/* Quadrature scaling only available in quadrature mode */
+		*scale = 0;
+
+		/* Synchronous function not supported in non-quadrature mode */
+		if (*synchronous_mode) {
+			*synchronous_mode = 0;
+			/* Disable synchronous function mode */
+			outb(0x60 | idr_cfg, base_offset);
+		}
+	} else {
+		*quadrature_mode = 1;
+
+		switch (function) {
+		case QUAD_COUNTER_FUNCTION_QUADRATURE_X1:
+			*scale = 0;
+			mode_cfg |= 0x8;
+			break;
+		case QUAD_COUNTER_FUNCTION_QUADRATURE_X2:
+			*scale = 1;
+			mode_cfg |= 0x10;
+			break;
+		case QUAD_COUNTER_FUNCTION_QUADRATURE_X4:
+			*scale = 2;
+			mode_cfg |= 0x18;
+			break;
+		}
+	}
+
+	/* Load mode configuration to Counter Mode Register */
+	outb(0x20 | mode_cfg, base_offset);
+
+	return 0;
+}
+
+static int quad8_direction_get(struct quad_counter_device *counter,
+	struct quad_counter_count *count,
+	enum quad_counter_direction *direction)
+{
+	const struct quad8_iio *const priv = counter->priv;
+	unsigned int ud_flag;
+	const unsigned int flag_addr = priv->base + 2 * count->id + 1;
+
+	/* U/D flag: nonzero = up, zero = down */
+	ud_flag = inb(flag_addr) & BIT(5);
+
+	*direction = (ud_flag) ? QUAD_COUNTER_DIRECTION_FORWARD :
+		QUAD_COUNTER_DIRECTION_BACKWARD;
+
+	return 0;
+}
+
+#define QUAD8_COUNT(_id, _cntname, _siganame, _sigbname) {	\
+	.id = _id,						\
+	.name = _cntname,					\
+	.signal_a = {						\
+		.id = 2 * _id,					\
+		.name = _siganame				\
+	},							\
+	.signal_b = {						\
+		.id = 2 * _id + 1,				\
+		.name = _sigbname				\
+	}							\
+}
+
+static const struct quad_counter_count quad8_counts[] = {
+	QUAD8_COUNT(0, "Channel 1 Count", "Channel 1 Quadrature A",
+		"Channel 1 Quadrature B"),
+	QUAD8_COUNT(1, "Channel 2 Count", "Channel 2 Quadrature A",
+		"Channel 2 Quadrature B"),
+	QUAD8_COUNT(2, "Channel 3 Count", "Channel 3 Quadrature A",
+		"Channel 3 Quadrature B"),
+	QUAD8_COUNT(3, "Channel 4 Count", "Channel 4 Quadrature A",
+		"Channel 4 Quadrature B"),
+	QUAD8_COUNT(4, "Channel 5 Count", "Channel 5 Quadrature A",
+		"Channel 5 Quadrature B"),
+	QUAD8_COUNT(5, "Channel 6 Count", "Channel 6 Quadrature A",
+		"Channel 6 Quadrature B"),
+	QUAD8_COUNT(6, "Channel 7 Count", "Channel 7 Quadrature A",
+		"Channel 7 Quadrature B"),
+	QUAD8_COUNT(7, "Channel 8 Count", "Channel 8 Quadrature A",
+		"Channel 8 Quadrature B")
+};
+
 static int quad8_probe(struct device *dev, unsigned int id)
 {
 	struct iio_dev *indio_dev;
-	struct quad8_iio *priv;
+	struct quad_counter_count *counts;
+	struct quad8_iio *quad8iio;
 	int i, j;
 	unsigned int base_offset;
+	int err;
 
-	indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
-	if (!indio_dev)
-		return -ENOMEM;
-
-	if (!devm_request_region(dev, base[id], QUAD8_EXTENT,
-		dev_name(dev))) {
+	if (!devm_request_region(dev, base[id], QUAD8_EXTENT, dev_name(dev))) {
 		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
 			base[id], base[id] + QUAD8_EXTENT);
 		return -EBUSY;
 	}
 
+	/* Allocate IIO device; this also allocates driver data structure */
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*quad8iio));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	/* Initialize IIO device */
 	indio_dev->info = &quad8_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->num_channels = ARRAY_SIZE(quad8_channels);
@@ -552,8 +765,26 @@ static int quad8_probe(struct device *dev, unsigned int id)
 	indio_dev->name = dev_name(dev);
 	indio_dev->dev.parent = dev;
 
-	priv = iio_priv(indio_dev);
-	priv->base = base[id];
+	/* Instantiate Quadrature Counter Counts */
+	counts = devm_kmemdup(dev, quad8_counts, sizeof(quad8_counts),
+		GFP_KERNEL);
+	if (!counts)
+		return -ENOMEM;
+
+	/* Initialize Quadrature Counter device and driver data */
+	quad8iio = iio_priv(indio_dev);
+	quad8iio->counter.name = dev_name(dev);
+	quad8iio->counter.parent = dev;
+	quad8iio->counter.signal_read = quad8_signal_read;
+	quad8iio->counter.count_read = quad8_count_read;
+	quad8iio->counter.count_write = quad8_count_write;
+	quad8iio->counter.function_get = quad8_function_get;
+	quad8iio->counter.function_set = quad8_function_set;
+	quad8iio->counter.direction_get = quad8_direction_get;
+	quad8iio->counter.counts = counts;
+	quad8iio->counter.num_counts = ARRAY_SIZE(quad8_counts);
+	quad8iio->counter.priv = quad8iio;
+	quad8iio->base = base[id];
 
 	/* Reset all counters and disable interrupt function */
 	outb(0x01, base[id] + 0x11);
@@ -579,7 +810,13 @@ static int quad8_probe(struct device *dev, unsigned int id)
 	/* Enable all counters */
 	outb(0x00, base[id] + 0x11);
 
-	return devm_iio_device_register(dev, indio_dev);
+	/* Register IIO device */
+	err = devm_iio_device_register(dev, indio_dev);
+	if (err)
+		return err;
+
+	/* Register Quadrature Counter device */
+	return devm_quad_counter_register(dev, &quad8iio->counter);
 }
 
 static struct isa_driver quad8_driver = {
Signature · 1 line
2.15.1
maintainer
#19 lore raw
In reply to William Breathitt Gray
Quoted 6 lines · On Thu, 14 Dec 2017 15:50:29 -0500 William Breathitt Gray…

Introduction
============

Apologies for going silent these past couple months just to return with a patchset over 3000 lines larger than the last -- I should have been releasing intermediate versions along the way so shame on me!

:) Sometimes it's better to wait until you are moderately happy with it yourself!

Quoted 8 lines

The
Counter system has effectively been rewritten anew, so I believe very little of the code in the previous versions of this patchset remain. However, the Generic Counter paradigm has pretty much remained the same so the theory should be familar. Regardless, I realize I'm dropping off this patchset near the winter holidays so I don't expect a review until well into January -- I'm just releasing this now before I myself head off on an end of year sabbatical.

It's at least a few hours into January so here goes before life gets properly busy again.

Quoted 17 lines

The most significant difference between this version and the previous, as well as part of the reason for the implementation code changes, is the complete separation of the Generic Counter system from IIO. I decided it was improper to build the Generic Counter system on top of IIO core: it was leading to ugly code, convulted hacks, and forced restrictions on the Generic Counter interface in order to appease the architecture of the IIO system. Most importantly, the IIO core code that was leveraged by the Generic Counter was so minor (essentially just the sysfs attribute support) that it did not justify the extensive hoop-jumping performed to make the code work.

So this patchset introduces the Generic Counter interface without the dependence on IIO code. This now gives the Generic Counter system the freedom to aptly represent counter devices without implementation compatibility concerns regarding other high-level subsystems.

Quoted 11 lines

This also makes sense ontologically I believe because whereas the IIO system appears more focused on representing the industrial I/O of a device and their configuration directly, the Generic Counter system is more concerned with the abstract representation of that counter device and the relationships and configurations within which define its operation at a high-level; a counter driver could in theory separately support both the high-level Generic Counter representation of the device as a whole (what are we counting conceptually, how much are we counting, etc.), as well as the low-level IIO representation of the individual inputs and outputs on that device (are the signals differential, do certain signals have current requirements, etc.).

I think there are concepts that over time may blur the lines more but agree with the basic point. I'm just planning to nick all your good ideas if they will improve IIO in turn.

Quoted 30 lines

Overview
========

This patchset may be divided into three main groups:

* Generic Counter
* Simple Counter
* Quadrature Counter

Each group begins with a patch introducing the implementation of the interface system, followed afterwards by documentation patches. I recommend reading through the documentation patches first to familiarize your with the interface itself before jumping into the source code for the implementation.

The Simple Counter and Quadrature Counter groups also have example driver code in the dummy-counter and 104-quad-8 patches respectively. The Simple Counter and Quadrature Counter systems themselves being subclasses of the Generic Counter may serve as example driver code for the Generic Counter interface -- though I may end up adding an explicit Generic Counter example in a later patch to the dummy-counter for easier reference.

Since the Generic Counter system no longer depends on IIO, I moved all Counter related source code to the drivers/iio/counter/ directory to keep everything contained together. In addition, with the IIO Kconfig dependency removed, the COUNTER menu appear now appears at the same level as the IIO menu:

Quoted 7 lines
        -> Device drivers
          -> Counter Support (COUNTER [=m])  

I'm not sure if I should move driver/iio/counter/ to driver/counter/ in order to match the Kconfig heirarchy or to keep it where it is to match the legacy IIO counter location established when we first added the 104-QUAD-8 driver.

I would move it out entirely - otherwise things are just confusing. You 'could' sit it in IIO (as in put it under the top level menu option) if you would prefer but I don't thing that really makes sense.

Quoted 16 lines

Paradigm updates
================

The Generic Counter paradigm has essentially remained the same from the previous patch, but I have made some minor updates. In particular, I've finally settled on a naming convention for the core components of a Counter:

COUNT
-----
A Count represents the count data for a set of Signals. A Count has a count function mode (e.g. "increase" or "quadrature x4") which represents the update behavior for the count data. A Count also has a set of one or more associated Signals.

Quoted 4 lines

This component was called "Value" in the previous patches. I believe "Count" is a more direct name for this data, and it also matches how datasheets and people commonly refer to this information in documentation.

Agreed - better name.

Quoted 24 lines

SIGNAL
------
A Signal represents a counter input data; this is the data that is typically analyzed by the counter to determine the count data. A Signal may be associated to one or more Counts.

The naming for this component has not changed since the previous patches. I believe "Signal" is a fitting enough name for the input data, as well as matching the common nomenclature for existing counter devices.

SYNAPSE
-------
A Synapse represents the association of a Signal with a respective Count. Signal data affects respective Count data, and the Synapse represents this relationship. The Synapse action mode (e.g. "rising edge" or "double pulse") specifies the Signal data condition which triggers the respective Count's count function evaluation to update the count data. It is possible for the Synapse action mode to be "none" if a Signal is associated with a Count but does not trigger the count function (e.g. the direction signal line for a Pulse-Direction encoding counter).

Quoted 5 lines

This component was called "Trigger" in the previous patches. I do not believe "Trigger" was a good name for two main reasons: it could easily be confused for the existing IIO trigger concept, and most importantly it does not convey the connection association aspect of the Count-Signal relationship.

An alternative here would be to use MAP as a number of similar 'connection' type arrangements in the kernel do. It doesn't really imply the 'how' element though so perhaps a new term is indeed better.

Quoted 45 lines

I settled on the "Synapse" name both due to etymology -- from Greek _sunapsis_ meaning "conjunction" -- as well as a biological analogy:
just as neurons connect and fire communication over synapses, so does a Counter Signal connect and fire communication to a Counter Count over a Counter Synapse.

Following the same naming convention and analogy, what was previously called trigger_mode is now known as action_mode, named in reference to action potential -- the condition in a neuron which triggers a fire communication over a synapse, just as a Counter Signal condition specified in the action_mode of a Counter Synapse triggers the count function evaluation for a Counter Count.

Counter classes descriptions
============================

The Generic Counter interface is the most general interface for supporting counter devices; if it qualifies as a Counter, then it can be represented by the Generic Counter interface. Unfortunately, the flexibility of the interface does result in a more cumbersome integration for driver authors: much of the components must be manually configured by the author, which can be a tedious task for large and complex counter devices.

To this end, two subclasses of the Generic Counter interface as introduced in this patchset: the Simple Counter interface, and the Quadrature Counter interface. Both of these interfaces inherit the Generic Counter paradigm, and may be seen as extensions to the interface which restrict the components to a respective specific class of counter devices in order to provide a more apt interface for such devices.

Simple Counter
--------------
Simple Counters are devices that count edge pulses on an input line (e.g. tally counters).

Since the relationship between Signals and Counts is known to be one-to-one, a simple_counter_count structure already contains the associated Signal member for the respective Count. A driver author no longer needs to worry about allocating a separate Signal and Synapse, nor about configuring the association between the respective Count and Signal; the Simple Counter interface abstracts away such details.

Quoted 7 lines

Furthermore, since the device type is known, component properties may be further defined and restricted: Count data is a signed integer, Signal data "low" and "high" state is set via enumeration constants, and so are count function and action mode restricted to well-defined "increase"/"decrease" and "none"/"rising edge"/"falling edge"/"both edges" enumeration constants respectively.

I do wonder a little on whether this is too restrictive to actually represent many devices.

Quoted 15 lines

Quadrature Counter
------------------
Quadrature Counters are devices that track position based on quadrature pair signals (e.g. rotary encoder counters).

Since the relationship between Signals and Counts is known to be a quadrature pair of Signals to each Count, a quad_counter_count structure already contains the associated Signal members for the respective Count. A driver author no longer needs to worry about allocating separate Signals and Synapses for each quadrature pair, nor about configuring the association between the respective Count and Signals; the Quadrature Counter interface abstracts away such details.

Quoted 6 lines

Furthermore, since the device type is known, component properties may be further defined and restricted: Count data is a signed integer, Signal data "low" and "high" state is set via enumeration constants, and so is count function mode restricted to well-defined enumeration constants to represent modes such as "pulse-direction" and "quadrature x4" for example.

Pulse direction is definitely not a quadrature counter... Maybe this needs a rename to dual-signal-counter or similar?

Another classic case here would be increment / decrement counters where a signal is used for each operation (counting items between two light gates
- used a lot in tracking products in the production industry).

Quoted 26 lines

Note how driver authors no longer need to interact with Synapses directly when utilizing the Simple Counter and Quadrature Counter interfaces. This should make it easier too for authors to add support since they don't need to fully understand the underlying Counter paradigm in order to take advantage of the interfaces -- just define the Counts and Signals, and they're ready to go.

Even more so, the Quadrature Counter interface takes it a step further and doesn't require action_modes to be explicitly set -- rather they are implicitly determined internally by the system based on the direction and function mode. Abstractions like these should make the Counter interface system as a whole robust enough to handle the diverse classes of counter devices out in the real world.

Compilation warnings
====================

There are three main compilation warnings which pop for this patchset. I've inspected these warnings and none are errors, however they do require some explanation.

* 104-quad-8: warning: enumeration value ‘QUAD_COUNTER_FUNCTION_PULSE_DIRECTION’ not handled in switch

Quoted 5 lines

The first warning is rather simple to explain: the QUAD_COUNTER_FUNCTION_PULSE_DIRECTION state is handled by the parent if statement's else condition, so an explicit case condition is not necessary. I can add a default case line to pacify the compiler, but since it would be empty the effort seems frivolous.

Do it anyway and put a comment of /* Should not get here */

Suppressing false warnings is useful from a code maintenance point of view.

Quoted 27 lines

In some sense as
well, a default case may make the switch logic less clear by implying the possibility of additional cases which are not possible in the context of that code path.

* simple-counter: warning: assignment discards ‘const’ qualifier from pointer target type
* quad-counter: warning: assignment discards ‘const’ qualifier from pointer target type

The second warning comes from the mapping of simple_counter_device_ext/quad_counter_device_ext, simple_counter_count_ext/quad_counter_count_ext, and simple_counter_signal_ext/quad_counter_signal_ext to the internal Counter counter_device_ext, counter_count_ext, and counter_signal_ext structures respectively.

The priv member of the counter_device_ext, counter_count_ext, or counter_signal_ext is leveraged to pass the respective simple_counter_device_ext/quad_counter_device_ext, simple_counter_count_ext/quad_counter_count_ext, or simple_counter_signal_ext/quad_counter_signal_ext structure to their respective read/write callback. The priv member is generic on purpose to allow any desired data to be passed; the supplied read/write callbacks should know the datatype of the passed-in priv argument so they cast it appropriately to access their expected data.

Quoted 5 lines

As such, the 'const' qualifier of the structures are thus discarded but subsequently cast back when the respective registered callback functions are called. Since this is the intended use case of the priv member -- to generically pass driver data for later recast -- I don't believe this warning needs to be rectified.

All warnings need to be rectified. Sorry but this noise will do two things:
1) Get you a patch every few weeks from someone fixing it.
2) Potentially make real warnings harder to see.

Sometimes we have to play games to work around them, but such is life.

Quoted 23 lines

* generic-counter: warning: passing argument 5 of ‘counter_attribute_create’ discards ‘const’ qualifier from pointer target type
* generic-counter: warning: passing argument 6 of ‘counter_attribute_create’ discards ‘const’ qualifier from pointer target type

The third warnings comes from a similar situation to the second warning:
a 'const' argument is passed generically via 'void *' for later recast. In this cast, I decided to create a generic function called counter_attribute_create in order to simplify the sysfs attribute registration code in the generic-counter.c file.

The counter_attribute_create function takes in read and write callbacks, as well as two optional generic data arguments to be stored as 'void *' (the component and component_data parameters). Using this setup allows the counter_attribute_create function to be the sole function necessary to create a desired Generic Counter sysfs attribute: read and write callbacks are passed along with relevant Counter component and data generically, which can be cast back later inside those read and write functions to match the expected datatype.

Quoted 7 lines

Using a generic counter_attribute_create function reduces duplicate code, but it does result in many superfluous compilation warnings. I can define new attribute_create functions specific to each type of sysfs attribute in order to pacify the warnings, but that seems to be such a waste to increase the amount of code with duplications that are unnecessary. What would you recommend; should I attempt to pacify these warnings or leave them be?

You must fix them I'm afraid.

Quoted 17 lines

Known TODO items
================

Although I've added the interface documentation files with rst file extensions, I still need to familiarize myself with Sphinx markup constructs to take advantage of the language. For example, I've copied verbatim several structure definitions into the documentation directly, but I believe this would be better left dynamically generated by using the relevant markup syntax. I'll try to clean up the documentation then once I've brushed up on Sphinx.

As noted in a previous patchset version, the signal_write callback should be removed from the interface; there are few if any cases where it makese sense to have a signal_write callback since Signals are always considered inputs in the context of the Counter paradigm.

Quoted 5 lines

I've retained the signal_write callback in this version since I'm unsure how to implement the dummy-counter Signal source. Benjamin Gaignard suggested implementing dummy-counter as a gpio-counter which could use gpio to provide a software quadratic counter. Is this the path I should take?

It would certainly work well and be simple enough for easy understanding. Also, it might be a useful driver in it's own right.

Quoted 6 lines

Furthermore, the dummy-counter driver defines its own single platform_device which restricts it to loading only a single instance. I can fix this to allow multiple instances in the next patchset version -- as suggested, I'll check out industrialio-sw-device.c for reference.

Quoted 6 lines

Right now the dummy-counter driver only has example code for the Simple Counter interface. It may be prudent to add example code for the Generic Counter and Quadrature Counter interfaces too. I think dummy-counter should serve as the reference driver implementation for all the Counter interfaces, so that driver authors have an example of how to integrate the particular interface they desire.

Such a driver is useful, but it doesn't add much if you have another, only slightly more complex real driver that also does the job. Perhaps do them all as gpio based drivers for example?

Quoted 10 lines

Finally, I only added very basic support for the Quadrature Counter interface in the 104-QUAD-8 driver. It's possible to support all existing IIO Counter sysfs attributes in the 104-QUAD-8 driver via corresponding quad_counter_device_ext, quad_counter_count_ext, and quad_counter_signal_ext structures, such that only the /sys/bus/counter/devices/counterX/ directory needs to be accessed to interact with the 104-QUAD-8 device. I'll try to add support for those remaining sysfs attributes in the next patchset version.

Quoted 2 lines

If I missed anything from the last patchset version review just remind me again and I'll add it to my TODO list. ;)

You are seriously optimistic if you think we can remember!

Jonathan

Quoted 44 lines

William Breathitt Gray (11):
iio: Introduce the Generic Counter interface
counter: Documentation: Add Generic Counter sysfs documentation
docs: Add Generic Counter interface documentation
counter: Introduce the Simple Counter interface
counter: Documentation: Add Simple Counter sysfs documentation
docs: Add Simple Counter interface documentation
counter: Add dummy counter driver
counter: Introduce the Quadrature Counter interface
counter: Documentation: Add Quadrature Counter sysfs documentation
docs: Add Quadrature Counter interface documentation
counter: 104-quad-8: Add Quadrature Counter interface support

 .../ABI/testing/sysfs-bus-counter-generic-sysfs    |  73 ++
 .../ABI/testing/sysfs-bus-counter-quadrature-sysfs |  76 ++
 .../ABI/testing/sysfs-bus-counter-simple-sysfs     |  61 ++
 Documentation/driver-api/iio/generic-counter.rst   | 434 +++++++++
 Documentation/driver-api/iio/index.rst             |   3 +
 Documentation/driver-api/iio/quad-counter.rst      | 444 +++++++++
 Documentation/driver-api/iio/simple-counter.rst    | 393 ++++++++
 MAINTAINERS                                        |   9 +
 drivers/iio/Kconfig                                |   3 +-
 drivers/iio/counter/104-quad-8.c                   | 257 +++++-
 drivers/iio/counter/Kconfig                        |  35 +-
 drivers/iio/counter/Makefile                       |   6 +
 drivers/iio/counter/dummy-counter.c                | 308 +++++++
 drivers/iio/counter/generic-counter.c              | 992 +++++++++++++++++++++
 drivers/iio/counter/quad-counter.c                 | 774 ++++++++++++++++
 drivers/iio/counter/simple-counter.c               | 734 +++++++++++++++
 include/linux/iio/counter.h                        | 629 +++++++++++++
 17 files changed, 5216 insertions(+), 15 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-quadrature-sysfs
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs
 create mode 100644 Documentation/driver-api/iio/generic-counter.rst
 create mode 100644 Documentation/driver-api/iio/quad-counter.rst
 create mode 100644 Documentation/driver-api/iio/simple-counter.rst
 create mode 100644 drivers/iio/counter/dummy-counter.c
 create mode 100644 drivers/iio/counter/generic-counter.c
 create mode 100644 drivers/iio/counter/quad-counter.c
 create mode 100644 drivers/iio/counter/simple-counter.c
 create mode 100644 include/linux/iio/counter.h
#20 lore raw

On Mon, 1 Jan 2018 11:16:30 +0000
Jonathan Cameron <[email protected]> wrote:

Sorry to top post but I just want to add some general comments across the whole series.

1) Basics look good to me. It all fits together well.
2) I'm concerned about the two 'simplified interfaces' for a couple of reasons:
a) They add a lot of code and I'm not convinced the simplifications justify that.
b) They aren't as generically applicable as we might want. For example, it's common for SoC Encoder blocks to operative in both the simple counter mode and the quadrature counter mode. To support that we have (I think) to go back to basics and do it ourselves from the generic counter interface. The TI eQEP IP does these modes for example.

So these simplifications serve two purposes (I think)
1) To enforce interface. This is nice (and I did some similar stuff in IIO for the same reason) but there is so much flexibility in the rest of the interface (from a code point of view) that I'm unsure this is significant.
2) To save on boiler plate. I'm not sure we save that much and that it couldn't mostly be achieved by providing some useful utility functions and standard enums / string arrays for the common cases.

We have to justify a couple of thousand lines of core code. To do that we need to be saving a reasonably multiple more than that in driver code.

The full setup for a generic_counter is not so complex that we need this stuff. Your examples make it all pretty clear what is going on and a couple of clean well commented drivers to act as a baseline for new implementations would get us much of the rest of the way.

So going well, but this aspect needs some more consideration.

I also think we need at least rough outlines of a few more drivers in here to convince people that there aren't any problems that this is too inflexible to cover. Hopefully an ST one will be forthcoming. If not we can do the exercise off datasheets.

Jonathan

Quoted 458 lines
Quoted 6 lines · On Thu, 14 Dec 2017 15:50:29 -0500 William Breathitt Gray…

Introduction
============

Apologies for going silent these past couple months just to return with a patchset over 3000 lines larger than the last -- I should have been releasing intermediate versions along the way so shame on me!

:) Sometimes it's better to wait until you are moderately happy with it yourself!

Quoted 8 lines

The
Counter system has effectively been rewritten anew, so I believe very little of the code in the previous versions of this patchset remain. However, the Generic Counter paradigm has pretty much remained the same so the theory should be familar. Regardless, I realize I'm dropping off this patchset near the winter holidays so I don't expect a review until well into January -- I'm just releasing this now before I myself head off on an end of year sabbatical.

It's at least a few hours into January so here goes before life gets properly busy again.

Quoted 17 lines

The most significant difference between this version and the previous, as well as part of the reason for the implementation code changes, is the complete separation of the Generic Counter system from IIO. I decided it was improper to build the Generic Counter system on top of IIO core: it was leading to ugly code, convulted hacks, and forced restrictions on the Generic Counter interface in order to appease the architecture of the IIO system. Most importantly, the IIO core code that was leveraged by the Generic Counter was so minor (essentially just the sysfs attribute support) that it did not justify the extensive hoop-jumping performed to make the code work.

So this patchset introduces the Generic Counter interface without the dependence on IIO code. This now gives the Generic Counter system the freedom to aptly represent counter devices without implementation compatibility concerns regarding other high-level subsystems.

Quoted 11 lines

This also makes sense ontologically I believe because whereas the IIO system appears more focused on representing the industrial I/O of a device and their configuration directly, the Generic Counter system is more concerned with the abstract representation of that counter device and the relationships and configurations within which define its operation at a high-level; a counter driver could in theory separately support both the high-level Generic Counter representation of the device as a whole (what are we counting conceptually, how much are we counting, etc.), as well as the low-level IIO representation of the individual inputs and outputs on that device (are the signals differential, do certain signals have current requirements, etc.).

I think there are concepts that over time may blur the lines more but agree with the basic point. I'm just planning to nick all your good ideas if they will improve IIO in turn.

Quoted 30 lines

Overview
========

This patchset may be divided into three main groups:

* Generic Counter
* Simple Counter
* Quadrature Counter

Each group begins with a patch introducing the implementation of the interface system, followed afterwards by documentation patches. I recommend reading through the documentation patches first to familiarize your with the interface itself before jumping into the source code for the implementation.

The Simple Counter and Quadrature Counter groups also have example driver code in the dummy-counter and 104-quad-8 patches respectively. The Simple Counter and Quadrature Counter systems themselves being subclasses of the Generic Counter may serve as example driver code for the Generic Counter interface -- though I may end up adding an explicit Generic Counter example in a later patch to the dummy-counter for easier reference.

Since the Generic Counter system no longer depends on IIO, I moved all Counter related source code to the drivers/iio/counter/ directory to keep everything contained together. In addition, with the IIO Kconfig dependency removed, the COUNTER menu appear now appears at the same level as the IIO menu:

Quoted 7 lines
        -> Device drivers
          -> Counter Support (COUNTER [=m])    

I'm not sure if I should move driver/iio/counter/ to driver/counter/ in order to match the Kconfig heirarchy or to keep it where it is to match the legacy IIO counter location established when we first added the 104-QUAD-8 driver.

I would move it out entirely - otherwise things are just confusing. You 'could' sit it in IIO (as in put it under the top level menu option) if you would prefer but I don't thing that really makes sense.

Quoted 16 lines

Paradigm updates
================

The Generic Counter paradigm has essentially remained the same from the previous patch, but I have made some minor updates. In particular, I've finally settled on a naming convention for the core components of a Counter:

COUNT
-----
A Count represents the count data for a set of Signals. A Count has a count function mode (e.g. "increase" or "quadrature x4") which represents the update behavior for the count data. A Count also has a set of one or more associated Signals.

Quoted 4 lines

This component was called "Value" in the previous patches. I believe "Count" is a more direct name for this data, and it also matches how datasheets and people commonly refer to this information in documentation.

Agreed - better name.

Quoted 24 lines

SIGNAL
------
A Signal represents a counter input data; this is the data that is typically analyzed by the counter to determine the count data. A Signal may be associated to one or more Counts.

The naming for this component has not changed since the previous patches. I believe "Signal" is a fitting enough name for the input data, as well as matching the common nomenclature for existing counter devices.

SYNAPSE
-------
A Synapse represents the association of a Signal with a respective Count. Signal data affects respective Count data, and the Synapse represents this relationship. The Synapse action mode (e.g. "rising edge" or "double pulse") specifies the Signal data condition which triggers the respective Count's count function evaluation to update the count data. It is possible for the Synapse action mode to be "none" if a Signal is associated with a Count but does not trigger the count function (e.g. the direction signal line for a Pulse-Direction encoding counter).

Quoted 5 lines

This component was called "Trigger" in the previous patches. I do not believe "Trigger" was a good name for two main reasons: it could easily be confused for the existing IIO trigger concept, and most importantly it does not convey the connection association aspect of the Count-Signal relationship.

An alternative here would be to use MAP as a number of similar 'connection' type arrangements in the kernel do. It doesn't really imply the 'how' element though so perhaps a new term is indeed better.

Quoted 45 lines

I settled on the "Synapse" name both due to etymology -- from Greek _sunapsis_ meaning "conjunction" -- as well as a biological analogy:
just as neurons connect and fire communication over synapses, so does a Counter Signal connect and fire communication to a Counter Count over a Counter Synapse.

Following the same naming convention and analogy, what was previously called trigger_mode is now known as action_mode, named in reference to action potential -- the condition in a neuron which triggers a fire communication over a synapse, just as a Counter Signal condition specified in the action_mode of a Counter Synapse triggers the count function evaluation for a Counter Count.

Counter classes descriptions
============================

The Generic Counter interface is the most general interface for supporting counter devices; if it qualifies as a Counter, then it can be represented by the Generic Counter interface. Unfortunately, the flexibility of the interface does result in a more cumbersome integration for driver authors: much of the components must be manually configured by the author, which can be a tedious task for large and complex counter devices.

To this end, two subclasses of the Generic Counter interface as introduced in this patchset: the Simple Counter interface, and the Quadrature Counter interface. Both of these interfaces inherit the Generic Counter paradigm, and may be seen as extensions to the interface which restrict the components to a respective specific class of counter devices in order to provide a more apt interface for such devices.

Simple Counter
--------------
Simple Counters are devices that count edge pulses on an input line (e.g. tally counters).

Since the relationship between Signals and Counts is known to be one-to-one, a simple_counter_count structure already contains the associated Signal member for the respective Count. A driver author no longer needs to worry about allocating a separate Signal and Synapse, nor about configuring the association between the respective Count and Signal; the Simple Counter interface abstracts away such details.

Quoted 7 lines

Furthermore, since the device type is known, component properties may be further defined and restricted: Count data is a signed integer, Signal data "low" and "high" state is set via enumeration constants, and so are count function and action mode restricted to well-defined "increase"/"decrease" and "none"/"rising edge"/"falling edge"/"both edges" enumeration constants respectively.

I do wonder a little on whether this is too restrictive to actually represent many devices.

Quoted 15 lines

Quadrature Counter
------------------
Quadrature Counters are devices that track position based on quadrature pair signals (e.g. rotary encoder counters).

Since the relationship between Signals and Counts is known to be a quadrature pair of Signals to each Count, a quad_counter_count structure already contains the associated Signal members for the respective Count. A driver author no longer needs to worry about allocating separate Signals and Synapses for each quadrature pair, nor about configuring the association between the respective Count and Signals; the Quadrature Counter interface abstracts away such details.

Quoted 6 lines

Furthermore, since the device type is known, component properties may be further defined and restricted: Count data is a signed integer, Signal data "low" and "high" state is set via enumeration constants, and so is count function mode restricted to well-defined enumeration constants to represent modes such as "pulse-direction" and "quadrature x4" for example.

Pulse direction is definitely not a quadrature counter... Maybe this needs a rename to dual-signal-counter or similar?

Another classic case here would be increment / decrement counters where a signal is used for each operation (counting items between two light gates
- used a lot in tracking products in the production industry).

Quoted 26 lines

Note how driver authors no longer need to interact with Synapses directly when utilizing the Simple Counter and Quadrature Counter interfaces. This should make it easier too for authors to add support since they don't need to fully understand the underlying Counter paradigm in order to take advantage of the interfaces -- just define the Counts and Signals, and they're ready to go.

Even more so, the Quadrature Counter interface takes it a step further and doesn't require action_modes to be explicitly set -- rather they are implicitly determined internally by the system based on the direction and function mode. Abstractions like these should make the Counter interface system as a whole robust enough to handle the diverse classes of counter devices out in the real world.

Compilation warnings
====================

There are three main compilation warnings which pop for this patchset. I've inspected these warnings and none are errors, however they do require some explanation.

* 104-quad-8: warning: enumeration value ‘QUAD_COUNTER_FUNCTION_PULSE_DIRECTION’ not handled in switch

Quoted 5 lines

The first warning is rather simple to explain: the QUAD_COUNTER_FUNCTION_PULSE_DIRECTION state is handled by the parent if statement's else condition, so an explicit case condition is not necessary. I can add a default case line to pacify the compiler, but since it would be empty the effort seems frivolous.

Do it anyway and put a comment of /* Should not get here */

Suppressing false warnings is useful from a code maintenance point of view.

Quoted 27 lines

In some sense as
well, a default case may make the switch logic less clear by implying the possibility of additional cases which are not possible in the context of that code path.

* simple-counter: warning: assignment discards ‘const’ qualifier from pointer target type
* quad-counter: warning: assignment discards ‘const’ qualifier from pointer target type

The second warning comes from the mapping of simple_counter_device_ext/quad_counter_device_ext, simple_counter_count_ext/quad_counter_count_ext, and simple_counter_signal_ext/quad_counter_signal_ext to the internal Counter counter_device_ext, counter_count_ext, and counter_signal_ext structures respectively.

The priv member of the counter_device_ext, counter_count_ext, or counter_signal_ext is leveraged to pass the respective simple_counter_device_ext/quad_counter_device_ext, simple_counter_count_ext/quad_counter_count_ext, or simple_counter_signal_ext/quad_counter_signal_ext structure to their respective read/write callback. The priv member is generic on purpose to allow any desired data to be passed; the supplied read/write callbacks should know the datatype of the passed-in priv argument so they cast it appropriately to access their expected data.

Quoted 5 lines

As such, the 'const' qualifier of the structures are thus discarded but subsequently cast back when the respective registered callback functions are called. Since this is the intended use case of the priv member -- to generically pass driver data for later recast -- I don't believe this warning needs to be rectified.

All warnings need to be rectified. Sorry but this noise will do two things:
1) Get you a patch every few weeks from someone fixing it.
2) Potentially make real warnings harder to see.

Sometimes we have to play games to work around them, but such is life.

Quoted 23 lines

* generic-counter: warning: passing argument 5 of ‘counter_attribute_create’ discards ‘const’ qualifier from pointer target type
* generic-counter: warning: passing argument 6 of ‘counter_attribute_create’ discards ‘const’ qualifier from pointer target type

The third warnings comes from a similar situation to the second warning:
a 'const' argument is passed generically via 'void *' for later recast. In this cast, I decided to create a generic function called counter_attribute_create in order to simplify the sysfs attribute registration code in the generic-counter.c file.

The counter_attribute_create function takes in read and write callbacks, as well as two optional generic data arguments to be stored as 'void *' (the component and component_data parameters). Using this setup allows the counter_attribute_create function to be the sole function necessary to create a desired Generic Counter sysfs attribute: read and write callbacks are passed along with relevant Counter component and data generically, which can be cast back later inside those read and write functions to match the expected datatype.

Quoted 7 lines

Using a generic counter_attribute_create function reduces duplicate code, but it does result in many superfluous compilation warnings. I can define new attribute_create functions specific to each type of sysfs attribute in order to pacify the warnings, but that seems to be such a waste to increase the amount of code with duplications that are unnecessary. What would you recommend; should I attempt to pacify these warnings or leave them be?

You must fix them I'm afraid.

Quoted 17 lines

Known TODO items
================

Although I've added the interface documentation files with rst file extensions, I still need to familiarize myself with Sphinx markup constructs to take advantage of the language. For example, I've copied verbatim several structure definitions into the documentation directly, but I believe this would be better left dynamically generated by using the relevant markup syntax. I'll try to clean up the documentation then once I've brushed up on Sphinx.

As noted in a previous patchset version, the signal_write callback should be removed from the interface; there are few if any cases where it makese sense to have a signal_write callback since Signals are always considered inputs in the context of the Counter paradigm.

Quoted 5 lines

I've retained the signal_write callback in this version since I'm unsure how to implement the dummy-counter Signal source. Benjamin Gaignard suggested implementing dummy-counter as a gpio-counter which could use gpio to provide a software quadratic counter. Is this the path I should take?

It would certainly work well and be simple enough for easy understanding. Also, it might be a useful driver in it's own right.

Quoted 6 lines

Furthermore, the dummy-counter driver defines its own single platform_device which restricts it to loading only a single instance. I can fix this to allow multiple instances in the next patchset version -- as suggested, I'll check out industrialio-sw-device.c for reference.

Quoted 6 lines

Right now the dummy-counter driver only has example code for the Simple Counter interface. It may be prudent to add example code for the Generic Counter and Quadrature Counter interfaces too. I think dummy-counter should serve as the reference driver implementation for all the Counter interfaces, so that driver authors have an example of how to integrate the particular interface they desire.

Such a driver is useful, but it doesn't add much if you have another, only slightly more complex real driver that also does the job. Perhaps do them all as gpio based drivers for example?

Quoted 10 lines

Finally, I only added very basic support for the Quadrature Counter interface in the 104-QUAD-8 driver. It's possible to support all existing IIO Counter sysfs attributes in the 104-QUAD-8 driver via corresponding quad_counter_device_ext, quad_counter_count_ext, and quad_counter_signal_ext structures, such that only the /sys/bus/counter/devices/counterX/ directory needs to be accessed to interact with the 104-QUAD-8 device. I'll try to add support for those remaining sysfs attributes in the next patchset version.

Quoted 2 lines

If I missed anything from the last patchset version review just remind me again and I'll add it to my TODO list. ;)

You are seriously optimistic if you think we can remember!

Jonathan

Quoted 35 lines

William Breathitt Gray (11):
iio: Introduce the Generic Counter interface
counter: Documentation: Add Generic Counter sysfs documentation
docs: Add Generic Counter interface documentation
counter: Introduce the Simple Counter interface
counter: Documentation: Add Simple Counter sysfs documentation
docs: Add Simple Counter interface documentation
counter: Add dummy counter driver
counter: Introduce the Quadrature Counter interface
counter: Documentation: Add Quadrature Counter sysfs documentation
docs: Add Quadrature Counter interface documentation
counter: 104-quad-8: Add Quadrature Counter interface support

 .../ABI/testing/sysfs-bus-counter-generic-sysfs    |  73 ++
 .../ABI/testing/sysfs-bus-counter-quadrature-sysfs |  76 ++
 .../ABI/testing/sysfs-bus-counter-simple-sysfs     |  61 ++
 Documentation/driver-api/iio/generic-counter.rst   | 434 +++++++++
 Documentation/driver-api/iio/index.rst             |   3 +
 Documentation/driver-api/iio/quad-counter.rst      | 444 +++++++++
 Documentation/driver-api/iio/simple-counter.rst    | 393 ++++++++
 MAINTAINERS                                        |   9 +
 drivers/iio/Kconfig                                |   3 +-
 drivers/iio/counter/104-quad-8.c                   | 257 +++++-
 drivers/iio/counter/Kconfig                        |  35 +-
 drivers/iio/counter/Makefile                       |   6 +
 drivers/iio/counter/dummy-counter.c                | 308 +++++++
 drivers/iio/counter/generic-counter.c              | 992 +++++++++++++++++++++
 drivers/iio/counter/quad-counter.c                 | 774 ++++++++++++++++
 drivers/iio/counter/simple-counter.c               | 734 +++++++++++++++
 include/linux/iio/counter.h                        | 629 +++++++++++++
 17 files changed, 5216 insertions(+), 15 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-quadrature-sysfs
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs
Quoted 9 lines
 create mode 100644 Documentation/driver-api/iio/generic-counter.rst
 create mode 100644 Documentation/driver-api/iio/quad-counter.rst
 create mode 100644 Documentation/driver-api/iio/simple-counter.rst
 create mode 100644 drivers/iio/counter/dummy-counter.c
 create mode 100644 drivers/iio/counter/generic-counter.c
 create mode 100644 drivers/iio/counter/quad-counter.c
 create mode 100644 drivers/iio/counter/simple-counter.c
 create mode 100644 include/linux/iio/counter.h

--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#21 lore raw

2018-01-01 14:04 GMT+01:00 Jonathan Cameron <[email protected]>:

Quoted 8 lines

On Mon, 1 Jan 2018 11:16:30 +0000
Jonathan Cameron <[email protected]> wrote:

Sorry to top post but I just want to add some general comments across the whole series.

1) Basics look good to me. It all fits together well.
2) I'm concerned about the two 'simplified interfaces' for a couple of re=

asons:

Quoted 1 line

a) They add a lot of code and I'm not convinced the simplifications justi=

fy that.

Quoted 1 line

b) They aren't as generically applicable as we might want. For example, i=

t's

Quoted 1 line

common for SoC Encoder blocks to operative in both the simple counter mod=

e and

Quoted 1 line

the quadrature counter mode. To support that we have (I think) to go bac=

k to

Quoted 1 line

basics and do it ourselves from the generic counter interface. The TI eQ=

EP

Quoted 4 lines

IP does these modes for example.

So these simplifications serve two purposes (I think)
1) To enforce interface. This is nice (and I did some similar stuff in I=

IO

Quoted 1 line

for the same reason) but there is so much flexibility in the rest of t=

he

Quoted 1 line

interface (from a code point of view) that I'm unsure this is signific=

ant.

Quoted 1 line

2) To save on boiler plate. I'm not sure we save that much and that it c=

ouldn't

Quoted 4 lines

mostly be achieved by providing some useful utility functions and standard enums / string arrays for the common cases.

We have to justify a couple of thousand lines of core code. To do that w=

e

Quoted 7 lines

need to be saving a reasonably multiple more than that in driver code.

The full setup for a generic_counter is not so complex that we need this stuff. Your examples make it all pretty clear what is going on and a couple of clean well commented drivers to act as a baseline for new implementations would get us much of the rest of the way.

Quoted 7 lines

So going well, but this aspect needs some more consideration.

I also think we need at least rough outlines of a few more drivers in here to convince people that there aren't any problems that this is too inflexible to cover. Hopefully an ST one will be forthcoming. If not we can do the exercise off datasheets.

Sorry for the long delay before answering to thread.
I have succesfully implement and test a quadrature encoder driver on stm32 timer part. Some clean up are need but the basic functions like setting the two supported modes (quadX2 or quadX4) supported by my hardware, counting, preset and direction are functional.

I have used the "simplified interface" so my driver is quite simple with only few functions to implement (~300 lines of code).
When this series will be upstream we can convert stm32 drivers to use it.

Thanks a lot for this work.
Benjamin

Quoted 9 lines

Jonathan

Quoted 7 lines
Quoted 4 lines · On Thu, 14 Dec 2017 15:50:29 -0500 William Breathitt Gray…

Introduction
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

Apologies for going silent these past couple months just to return wit=

h

Quoted 10 lines
Quoted 10 lines
Quoted 2 lines

a patchset over 3000 lines larger than the last -- I should have been releasing intermediate versions along the way so shame on me!

:) Sometimes it's better to wait until you are moderately happy with it yourself!

Quoted 4 lines

The
Counter system has effectively been rewritten anew, so I believe very little of the code in the previous versions of this patchset remain. However, the Generic Counter paradigm has pretty much remained the sam=

e

Quoted 1 line
Quoted 1 line
Quoted 1 line

so the theory should be familar. Regardless, I realize I'm dropping of=

f

Quoted 1 line
Quoted 1 line
Quoted 1 line

this patchset near the winter holidays so I don't expect a review unti=

l

Quoted 7 lines
Quoted 7 lines
Quoted 2 lines

well into January -- I'm just releasing this now before I myself head off on an end of year sabbatical.

It's at least a few hours into January so here goes before life gets properly busy again.

Quoted 1 line
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

The most significant difference between this version and the previous, as well as part of the reason for the implementation code changes, is the complete separation of the Generic Counter system from IIO. I decided it was improper to build the Generic Counter system on top of IIO core: it was leading to ugly code, convulted hacks, and forced restrictions on the Generic Counter interface in order to appease the architecture of the IIO system. Most importantly, the IIO core code th=

at

Quoted 1 line
Quoted 1 line
Quoted 1 line

was leveraged by the Generic Counter was so minor (essentially just th=

e

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

sysfs attribute support) that it did not justify the extensive hoop-jumping performed to make the code work.

So this patchset introduces the Generic Counter interface without the dependence on IIO code. This now gives the Generic Counter system the freedom to aptly represent counter devices without implementation compatibility concerns regarding other high-level subsystems.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

This also makes sense ontologically I believe because whereas the IIO system appears more focused on representing the industrial I/O of a device and their configuration directly, the Generic Counter system is more concerned with the abstract representation of that counter device and the relationships and configurations within which define its operation at a high-level; a counter driver could in theory separately support both the high-level Generic Counter representation of the devi=

ce

Quoted 1 line
Quoted 1 line
Quoted 1 line

as a whole (what are we counting conceptually, how much are we countin=

g,

Quoted 14 lines
Quoted 14 lines
Quoted 3 lines

etc.), as well as the low-level IIO representation of the individual inputs and outputs on that device (are the signals differential, do certain signals have current requirements, etc.).

I think there are concepts that over time may blur the lines more but agree with the basic point. I'm just planning to nick all your good ideas if they will improve IIO in turn.

Quoted 6 lines

Overview
=3D=3D=3D=3D=3D=3D=3D=3D

This patchset may be divided into three main groups:

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

* Generic Counter
* Simple Counter
* Quadrature Counter

Each group begins with a patch introducing the implementation of the interface system, followed afterwards by documentation patches. I recommend reading through the documentation patches first to familiari=

ze

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

your with the interface itself before jumping into the source code for the implementation.

The Simple Counter and Quadrature Counter groups also have example driver code in the dummy-counter and 104-quad-8 patches respectively. The Simple Counter and Quadrature Counter systems themselves being subclasses of the Generic Counter may serve as example driver code for the Generic Counter interface -- though I may end up adding an explici=

t

Quoted 1 line
Quoted 1 line
Quoted 1 line

Generic Counter example in a later patch to the dummy-counter for easi=

er

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

reference.

Since the Generic Counter system no longer depends on IIO, I moved all Counter related source code to the drivers/iio/counter/ directory to keep everything contained together. In addition, with the IIO Kconfig dependency removed, the COUNTER menu appear now appears at the same level as the IIO menu:

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
        -> Device drivers
          -> Counter Support (COUNTER [=3Dm])

I'm not sure if I should move driver/iio/counter/ to driver/counter/ i=

n

Quoted 1 line
Quoted 1 line
Quoted 1 line

order to match the Kconfig heirarchy or to keep it where it is to matc=

h

Quoted 8 lines
Quoted 8 lines
Quoted 2 lines

the legacy IIO counter location established when we first added the 104-QUAD-8 driver.

I would move it out entirely - otherwise things are just confusing. You 'could' sit it in IIO (as in put it under the top level menu option) if you would prefer but I don't thing that really makes sense.

Quoted 1 line
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

Paradigm updates
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

The Generic Counter paradigm has essentially remained the same from th=

e

Quoted 1 line
Quoted 1 line
Quoted 1 line

previous patch, but I have made some minor updates. In particular, I'v=

e

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

finally settled on a naming convention for the core components of a Counter:

COUNT
-----
A Count represents the count data for a set of Signals. A Coun=

t

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

has a count function mode (e.g. "increase" or "quadrature x4") which represents the update behavior for the count data. A Cou=

nt

Quoted 7 lines
Quoted 7 lines
Quoted 6 lines

also has a set of one or more associated Signals.

This component was called "Value" in the previous patches. I believe "Count" is a more direct name for this data, and it also matches how datasheets and people commonly refer to this information in documentation.

Quoted 6 lines
Quoted 6 lines

Agreed - better name.

Quoted 4 lines

SIGNAL
------
A Signal represents a counter input data; this is the data tha=

t

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

is typically analyzed by the counter to determine the count data. A Signal may be associated to one or more Counts.

The naming for this component has not changed since the previous patches. I believe "Signal" is a fitting enough name for the input data, as well as matching the common nomenclature for existing counter devices.

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

SYNAPSE
-------
A Synapse represents the association of a Signal with a respective Count. Signal data affects respective Count data, a=

nd

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

the Synapse represents this relationship. The Synapse action mode (e.g. "rising edge" or "double pulse") specifies the Sign=

al

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

data condition which triggers the respective Count's count function evaluation to update the count data. It is possible f=

or

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

the Synapse action mode to be "none" if a Signal is associated with a Count but does not trigger the count function (e.g. the direction signal line for a Pulse-Direction encoding counter).

This component was called "Trigger" in the previous patches. I do not believe "Trigger" was a good name for two main reasons: it could easil=

y

Quoted 10 lines
Quoted 10 lines
Quoted 3 lines

be confused for the existing IIO trigger concept, and most importantly it does not convey the connection association aspect of the Count-Signal relationship.

An alternative here would be to use MAP as a number of similar 'connection' type arrangements in the kernel do. It doesn't really imply the 'how' element though so perhaps a new term is indeed better.

Quoted 1 line
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

I settled on the "Synapse" name both due to etymology -- from Greek _sunapsis_ meaning "conjunction" -- as well as a biological analogy:
just as neurons connect and fire communication over synapses, so does =

a

Quoted 1 line
Quoted 1 line
Quoted 1 line

Counter Signal connect and fire communication to a Counter Count over =

a

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines

Counter Synapse.

Following the same naming convention and analogy, what was previously called trigger_mode is now known as action_mode, named in reference to action potential -- the condition in a neuron which triggers a fire communication over a synapse, just as a Counter Signal condition specified in the action_mode of a Counter Synapse triggers the count function evaluation for a Counter Count.

Counter classes descriptions =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=

=3D=3D=3D=3D=3D

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

The Generic Counter interface is the most general interface for supporting counter devices; if it qualifies as a Counter, then it can =

be

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

represented by the Generic Counter interface. Unfortunately, the flexibility of the interface does result in a more cumbersome integration for driver authors: much of the components must be manuall=

y

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

configured by the author, which can be a tedious task for large and complex counter devices.

To this end, two subclasses of the Generic Counter interface as introduced in this patchset: the Simple Counter interface, and the Quadrature Counter interface. Both of these interfaces inherit the Generic Counter paradigm, and may be seen as extensions to the interfa=

ce

Quoted 1 line
Quoted 1 line
Quoted 1 line

which restrict the components to a respective specific class of counte=

r

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

devices in order to provide a more apt interface for such devices.

Simple Counter
--------------
Simple Counters are devices that count edge pulses on an input line (e.g. tally counters).

Since the relationship between Signals and Counts is known to =

be

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

one-to-one, a simple_counter_count structure already contains the associated Signal member for the respective Count. A drive=

r

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

author no longer needs to worry about allocating a separate Signal and Synapse, nor about configuring the association between the respective Count and Signal; the Simple Counter interface abstracts away such details.

Furthermore, since the device type is known, component properties may be further defined and restricted: Count data i=

s

Quoted 1 line
Quoted 1 line
Quoted 1 line

a signed integer, Signal data "low" and "high" state is set vi=

a

Quoted 1 line
Quoted 1 line
Quoted 1 line

enumeration constants, and so are count function and action mo=

de

Quoted 7 lines
Quoted 7 lines
Quoted 3 lines

restricted to well-defined "increase"/"decrease" and "none"/"rising edge"/"falling edge"/"both edges" enumeration constants respectively.

I do wonder a little on whether this is too restrictive to actually represent many devices.

Quoted 1 line
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

Quadrature Counter
------------------
Quadrature Counters are devices that track position based on quadrature pair signals (e.g. rotary encoder counters).

Since the relationship between Signals and Counts is known to =

be

Quoted 1 line
Quoted 1 line
Quoted 1 line

a quadrature pair of Signals to each Count, a quad_counter_cou=

nt

Quoted 1 line
Quoted 1 line
Quoted 1 line

structure already contains the associated Signal members for t=

he

Quoted 1 line
Quoted 1 line
Quoted 1 line

respective Count. A driver author no longer needs to worry abo=

ut

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

allocating separate Signals and Synapses for each quadrature pair, nor about configuring the association between the respective Count and Signals; the Quadrature Counter interface abstracts away such details.

Furthermore, since the device type is known, component properties may be further defined and restricted: Count data i=

s

Quoted 1 line
Quoted 1 line
Quoted 1 line

a signed integer, Signal data "low" and "high" state is set vi=

a

Quoted 1 line
Quoted 1 line
Quoted 1 line

enumeration constants, and so is count function mode restricte=

d

Quoted 1 line
Quoted 1 line
Quoted 1 line

to well-defined enumeration constants to represent modes such =

as

Quoted 3 lines
Quoted 3 lines
Quoted 1 line

"pulse-direction" and "quadrature x4" for example.

Pulse direction is definitely not a quadrature counter... Maybe this ne=

eds

Quoted 4 lines
Quoted 4 lines

a rename to dual-signal-counter or similar?

Another classic case here would be increment / decrement counters where a signal is used for each operation (counting items between two light ga=

tes

Quoted 8 lines
Quoted 8 lines

- used a lot in tracking products in the production industry).

Quoted 6 lines

Note how driver authors no longer need to interact with Synapses directly when utilizing the Simple Counter and Quadrature Counter interfaces. This should make it easier too for authors to add support since they don't need to fully understand the underlying Counter paradigm in order to take advantage of the interfaces -- just define t=

he

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

Counts and Signals, and they're ready to go.

Even more so, the Quadrature Counter interface takes it a step further and doesn't require action_modes to be explicitly set -- rather they a=

re

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

implicitly determined internally by the system based on the direction and function mode. Abstractions like these should make the Counter interface system as a whole robust enough to handle the diverse classe=

s

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines

of counter devices out in the real world.

Compilation warnings =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

There are three main compilation warnings which pop for this patchset. I've inspected these warnings and none are errors, however they do require some explanation.

* 104-quad-8: warning: enumeration value =E2=80=98QUAD_COUNTER_FUNCTION_PULSE_DIRECTION=E2=80=

=99 not handled in

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

switch

The first warning is rather simple to explain: the QUAD_COUNTER_FUNCTION_PULSE_DIRECTION state is handled by the parent i=

f

Quoted 7 lines
Quoted 7 lines
Quoted 3 lines

statement's else condition, so an explicit case condition is not necessary. I can add a default case line to pacify the compiler, but since it would be empty the effort seems frivolous.

Do it anyway and put a comment of /* Should not get here */

Suppressing false warnings is useful from a code maintenance point of vi=

ew.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

In some sense as
well, a default case may make the switch logic less clear by implying the possibility of additional cases which are not possible in the context of that code path.

* simple-counter: warning: assignment discards =E2=80=98const=

=E2=80=99 qualifier

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

from pointer target type
* quad-counter: warning: assignment discards =E2=80=98const=E2=

=80=99 qualifier

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

from pointer target type

The second warning comes from the mapping of simple_counter_device_ext/quad_counter_device_ext, simple_counter_count_ext/quad_counter_count_ext, and simple_counter_signal_ext/quad_counter_signal_ext to the internal Counter counter_device_ext, counter_count_ext, and counter_signal_ext structures respectively.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

The priv member of the counter_device_ext, counter_count_ext, or counter_signal_ext is leveraged to pass the respective simple_counter_device_ext/quad_counter_device_ext, simple_counter_count_ext/quad_counter_count_ext, or simple_counter_signal_ext/quad_counter_signal_ext structure to their respective read/write callback. The priv member is generic on purpose =

to

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

allow any desired data to be passed; the supplied read/write callbacks should know the datatype of the passed-in priv argument so they cast i=

t

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

appropriately to access their expected data.

As such, the 'const' qualifier of the structures are thus discarded bu=

t

Quoted 1 line
Quoted 1 line
Quoted 1 line

subsequently cast back when the respective registered callback functio=

ns

Quoted 1 line
Quoted 1 line
Quoted 1 line

are called. Since this is the intended use case of the priv member -- =

to

Quoted 4 lines
Quoted 4 lines
Quoted 2 lines

generically pass driver data for later recast -- I don't believe this warning needs to be rectified.

All warnings need to be rectified. Sorry but this noise will do two thi=

ngs:

Quoted 8 lines
Quoted 8 lines

1) Get you a patch every few weeks from someone fixing it.
2) Potentially make real warnings harder to see.

Sometimes we have to play games to work around them, but such is life.

Quoted 3 lines

* generic-counter: warning: passing argument 5 of =E2=80=98counter_attribute_create=E2=80=99 discards =

=E2=80=98const=E2=80=99 qualifier

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

from pointer target type
* generic-counter: warning: passing argument 6 of =E2=80=98counter_attribute_create=E2=80=99 discards =

=E2=80=98const=E2=80=99 qualifier

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

from pointer target type

The third warnings comes from a similar situation to the second warnin=

g:

Quoted 1 line
Quoted 1 line
Quoted 1 line

a 'const' argument is passed generically via 'void *' for later recast=

.

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

In this cast, I decided to create a generic function called counter_attribute_create in order to simplify the sysfs attribute registration code in the generic-counter.c file.

The counter_attribute_create function takes in read and write callback=

s,

Quoted 1 line
Quoted 1 line
Quoted 1 line

as well as two optional generic data arguments to be stored as 'void *=

'

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

(the component and component_data parameters). Using this setup allows the counter_attribute_create function to be the sole function necessar=

y

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

to create a desired Generic Counter sysfs attribute: read and write callbacks are passed along with relevant Counter component and data generically, which can be cast back later inside those read and write functions to match the expected datatype.

Using a generic counter_attribute_create function reduces duplicate code, but it does result in many superfluous compilation warnings. I c=

an

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

define new attribute_create functions specific to each type of sysfs attribute in order to pacify the warnings, but that seems to be such a waste to increase the amount of code with duplications that are unnecessary. What would you recommend; should I attempt to pacify thes=

e

Quoted 5 lines
Quoted 5 lines
Quoted 1 line

warnings or leave them be?

You must fix them I'm afraid.

Quoted 1 line
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

Known TODO items
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

Although I've added the interface documentation files with rst file extensions, I still need to familiarize myself with Sphinx markup constructs to take advantage of the language. For example, I've copied verbatim several structure definitions into the documentation directly=

,

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

but I believe this would be better left dynamically generated by using the relevant markup syntax. I'll try to clean up the documentation the=

n

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

once I've brushed up on Sphinx.

As noted in a previous patchset version, the signal_write callback should be removed from the interface; there are few if any cases where it makese sense to have a signal_write callback since Signals are always considered inputs in the context of the Counter paradigm.

I've retained the signal_write callback in this version since I'm unsu=

re

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

how to implement the dummy-counter Signal source. Benjamin Gaignard suggested implementing dummy-counter as a gpio-counter which could use gpio to provide a software quadratic counter. Is this the path I shoul=

d

Quoted 3 lines
Quoted 3 lines
Quoted 1 line

take?

It would certainly work well and be simple enough for easy understanding=

.

Quoted 6 lines
Quoted 6 lines

Also, it might be a useful driver in it's own right.

Quoted 4 lines

Furthermore, the dummy-counter driver defines its own single platform_device which restricts it to loading only a single instance. I can fix this to allow multiple instances in the next patchset versio=

n

Quoted 1 line
Quoted 1 line
Quoted 1 line

-- as suggested, I'll check out industrialio-sw-device.c for reference=

.

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

Right now the dummy-counter driver only has example code for the Simpl=

e

Quoted 1 line
Quoted 1 line
Quoted 1 line

Counter interface. It may be prudent to add example code for the Gener=

ic

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

Counter and Quadrature Counter interfaces too. I think dummy-counter should serve as the reference driver implementation for all the Counte=

r

Quoted 37 lines
Quoted 37 lines
Quoted 2 lines

interfaces, so that driver authors have an example of how to integrate the particular interface they desire.

Such a driver is useful, but it doesn't add much if you have another, only slightly more complex real driver that also does the job. Perhaps do them all as gpio based drivers for example?

Quoted 10 lines

Finally, I only added very basic support for the Quadrature Counter interface in the 104-QUAD-8 driver. It's possible to support all existing IIO Counter sysfs attributes in the 104-QUAD-8 driver via corresponding quad_counter_device_ext, quad_counter_count_ext, and quad_counter_signal_ext structures, such that only the /sys/bus/counter/devices/counterX/ directory needs to be accessed to interact with the 104-QUAD-8 device. I'll try to add support for those remaining sysfs attributes in the next patchset version.

Quoted 2 lines

If I missed anything from the last patchset version review just remind me again and I'll add it to my TODO list. ;)

You are seriously optimistic if you think we can remember!

Jonathan

Quoted 14 lines

William Breathitt Gray (11):
iio: Introduce the Generic Counter interface
counter: Documentation: Add Generic Counter sysfs documentation
docs: Add Generic Counter interface documentation
counter: Introduce the Simple Counter interface
counter: Documentation: Add Simple Counter sysfs documentation
docs: Add Simple Counter interface documentation
counter: Add dummy counter driver
counter: Introduce the Quadrature Counter interface
counter: Documentation: Add Quadrature Counter sysfs documentation
docs: Add Quadrature Counter interface documentation
counter: 104-quad-8: Add Quadrature Counter interface support

Quoted 14 lines
Quoted 6 lines
Quoted 6 lines
 .../ABI/testing/sysfs-bus-counter-generic-sysfs    |  73 ++
 .../ABI/testing/sysfs-bus-counter-quadrature-sysfs |  76 ++
 .../ABI/testing/sysfs-bus-counter-simple-sysfs     |  61 ++
 Documentation/driver-api/iio/generic-counter.rst   | 434 +++++++++
 Documentation/driver-api/iio/index.rst             |   3 +
 Documentation/driver-api/iio/quad-counter.rst      | 444 +++++++++
Quoted 8 lines
Quoted 8 lines
 Documentation/driver-api/iio/simple-counter.rst    | 393 ++++++++
 MAINTAINERS                                        |   9 +
 drivers/iio/Kconfig                                |   3 +-
 drivers/iio/counter/104-quad-8.c                   | 257 +++++-
 drivers/iio/counter/Kconfig                        |  35 +-
 drivers/iio/counter/Makefile                       |   6 +
 drivers/iio/counter/dummy-counter.c                | 308 +++++++

drivers/iio/counter/generic-counter.c | 992 ++++++++++++=

+++++++++

Quoted 1 line
Quoted 1 line
Quoted 1 line

drivers/iio/counter/quad-counter.c | 774 ++++++++++++=

++++

Quoted 1 line
Quoted 1 line
Quoted 1 line

drivers/iio/counter/simple-counter.c | 734 ++++++++++++=

+++

Quoted 1 line
Quoted 1 line
Quoted 1 line

include/linux/iio/counter.h | 629 ++++++++++++=

+

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
 17 files changed, 5216 insertions(+), 15 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-generi=

c-sysfs

Quoted 1 line
Quoted 1 line
Quoted 1 line
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-quadra=

ture-sysfs

Quoted 1 line
Quoted 1 line
Quoted 1 line
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-simple=

-sysfs

Quoted 15 lines
Quoted 14 lines
Quoted 9 lines
 create mode 100644 Documentation/driver-api/iio/generic-counter.rst
 create mode 100644 Documentation/driver-api/iio/quad-counter.rst
 create mode 100644 Documentation/driver-api/iio/simple-counter.rst
 create mode 100644 drivers/iio/counter/dummy-counter.c
 create mode 100644 drivers/iio/counter/generic-counter.c
 create mode 100644 drivers/iio/counter/quad-counter.c
 create mode 100644 drivers/iio/counter/simple-counter.c
 create mode 100644 include/linux/iio/counter.h

--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#22 lore raw

2018-01-15 10:02 GMT+01:00 Benjamin Gaignard <[email protected]>= :

Quoted 1 line

2018-01-01 14:04 GMT+01:00 Jonathan Cameron <[email protected]>=

:

Quoted 8 lines
Quoted 8 lines

On Mon, 1 Jan 2018 11:16:30 +0000
Jonathan Cameron <[email protected]> wrote:

Sorry to top post but I just want to add some general comments across the whole series.

1) Basics look good to me. It all fits together well.
2) I'm concerned about the two 'simplified interfaces' for a couple of r=

easons:

Quoted 1 line
Quoted 1 line

a) They add a lot of code and I'm not convinced the simplifications just=

ify that.

Quoted 1 line
Quoted 1 line

b) They aren't as generically applicable as we might want. For example, =

it's

Quoted 1 line
Quoted 1 line

common for SoC Encoder blocks to operative in both the simple counter mo=

de and

Quoted 1 line
Quoted 1 line

the quadrature counter mode. To support that we have (I think) to go ba=

ck to

Quoted 1 line
Quoted 1 line

basics and do it ourselves from the generic counter interface. The TI e=

QEP

Quoted 4 lines
Quoted 4 lines

IP does these modes for example.

So these simplifications serve two purposes (I think)
1) To enforce interface. This is nice (and I did some similar stuff in =

IIO

Quoted 1 line
Quoted 1 line

for the same reason) but there is so much flexibility in the rest of =

the

Quoted 1 line
Quoted 1 line

interface (from a code point of view) that I'm unsure this is signifi=

cant.

Quoted 1 line
Quoted 1 line

2) To save on boiler plate. I'm not sure we save that much and that it =

couldn't

Quoted 4 lines
Quoted 4 lines

mostly be achieved by providing some useful utility functions and standard enums / string arrays for the common cases.

We have to justify a couple of thousand lines of core code. To do that =

we

Quoted 21 lines
Quoted 7 lines

need to be saving a reasonably multiple more than that in driver code.

The full setup for a generic_counter is not so complex that we need this stuff. Your examples make it all pretty clear what is going on and a couple of clean well commented drivers to act as a baseline for new implementations would get us much of the rest of the way.

Quoted 7 lines

So going well, but this aspect needs some more consideration.

I also think we need at least rough outlines of a few more drivers in here to convince people that there aren't any problems that this is too inflexible to cover. Hopefully an ST one will be forthcoming. If not we can do the exercise off datasheets.

Sorry for the long delay before answering to thread.
I have succesfully implement and test a quadrature encoder driver on stm32 timer part. Some clean up are need but the basic functions like setting the two supported modes (quadX2 or quadX4) supported by my hardware, counting, preset and direction are functional.

Quoted 6 lines

I have used the "simplified interface" so my driver is quite simple with only few functions to implement (~300 lines of code).
When this series will be upstream we can convert stm32 drivers to use it.

Thanks a lot for this work.
Benjamin

Any news about those patches ?

Regards,
Benjamin

Quoted 10 lines
Quoted 10 lines

Jonathan

Quoted 7 lines
Quoted 4 lines · On Thu, 14 Dec 2017 15:50:29 -0500 William Breathitt Gray…

Introduction
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

Apologies for going silent these past couple months just to return wi=

th

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 2 lines

a patchset over 3000 lines larger than the last -- I should have been releasing intermediate versions along the way so shame on me!

:) Sometimes it's better to wait until you are moderately happy with it yourself!

Quoted 4 lines

The
Counter system has effectively been rewritten anew, so I believe very little of the code in the previous versions of this patchset remain. However, the Generic Counter paradigm has pretty much remained the sa=

me

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

so the theory should be familar. Regardless, I realize I'm dropping o=

ff

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

this patchset near the winter holidays so I don't expect a review unt=

il

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines

well into January -- I'm just releasing this now before I myself head off on an end of year sabbatical.

It's at least a few hours into January so here goes before life gets properly busy again.

Quoted 2 lines

The most significant difference between this version and the previous=

,

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

as well as part of the reason for the implementation code changes, is the complete separation of the Generic Counter system from IIO. I decided it was improper to build the Generic Counter system on top of IIO core: it was leading to ugly code, convulted hacks, and forced restrictions on the Generic Counter interface in order to appease the architecture of the IIO system. Most importantly, the IIO core code t=

hat

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

was leveraged by the Generic Counter was so minor (essentially just t=

he

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines

sysfs attribute support) that it did not justify the extensive hoop-jumping performed to make the code work.

So this patchset introduces the Generic Counter interface without the dependence on IIO code. This now gives the Generic Counter system the freedom to aptly represent counter devices without implementation compatibility concerns regarding other high-level subsystems.

This also makes sense ontologically I believe because whereas the IIO system appears more focused on representing the industrial I/O of a device and their configuration directly, the Generic Counter system i=

s

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

more concerned with the abstract representation of that counter devic=

e

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

and the relationships and configurations within which define its operation at a high-level; a counter driver could in theory separatel=

y

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

support both the high-level Generic Counter representation of the dev=

ice

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

as a whole (what are we counting conceptually, how much are we counti=

ng,

Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
Quoted 3 lines

etc.), as well as the low-level IIO representation of the individual inputs and outputs on that device (are the signals differential, do certain signals have current requirements, etc.).

I think there are concepts that over time may blur the lines more but agree with the basic point. I'm just planning to nick all your good ideas if they will improve IIO in turn.

Quoted 6 lines

Overview
=3D=3D=3D=3D=3D=3D=3D=3D

This patchset may be divided into three main groups:

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

* Generic Counter
* Simple Counter
* Quadrature Counter

Each group begins with a patch introducing the implementation of the interface system, followed afterwards by documentation patches. I recommend reading through the documentation patches first to familiar=

ize

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

your with the interface itself before jumping into the source code fo=

r

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

the implementation.

The Simple Counter and Quadrature Counter groups also have example driver code in the dummy-counter and 104-quad-8 patches respectively. The Simple Counter and Quadrature Counter systems themselves being subclasses of the Generic Counter may serve as example driver code fo=

r

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

the Generic Counter interface -- though I may end up adding an explic=

it

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

Generic Counter example in a later patch to the dummy-counter for eas=

ier

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

reference.

Since the Generic Counter system no longer depends on IIO, I moved al=

l

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

Counter related source code to the drivers/iio/counter/ directory to keep everything contained together. In addition, with the IIO Kconfig dependency removed, the COUNTER menu appear now appears at the same level as the IIO menu:

        -> Device drivers
          -> Counter Support (COUNTER [=3Dm])

I'm not sure if I should move driver/iio/counter/ to driver/counter/ =

in

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

order to match the Kconfig heirarchy or to keep it where it is to mat=

ch

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines

the legacy IIO counter location established when we first added the 104-QUAD-8 driver.

I would move it out entirely - otherwise things are just confusing. You 'could' sit it in IIO (as in put it under the top level menu option=

)

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

if you would prefer but I don't thing that really makes sense.

Quoted 5 lines

Paradigm updates
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

The Generic Counter paradigm has essentially remained the same from t=

he

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

previous patch, but I have made some minor updates. In particular, I'=

ve

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

finally settled on a naming convention for the core components of a Counter:

COUNT
-----
A Count represents the count data for a set of Signals. A Cou=

nt

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

has a count function mode (e.g. "increase" or "quadrature x4"=

)

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

which represents the update behavior for the count data. A Co=

unt

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines

also has a set of one or more associated Signals.

This component was called "Value" in the previous patches. I believe "Count" is a more direct name for this data, and it also matches how datasheets and people commonly refer to this information in documentation.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

Agreed - better name.

Quoted 4 lines

SIGNAL
------
A Signal represents a counter input data; this is the data th=

at

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

is typically analyzed by the counter to determine the count data. A Signal may be associated to one or more Counts.

The naming for this component has not changed since the previous patches. I believe "Signal" is a fitting enough name for the input data, as well as matching the common nomenclature for existing counte=

r

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

devices.

SYNAPSE
-------
A Synapse represents the association of a Signal with a respective Count. Signal data affects respective Count data, =

and

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

the Synapse represents this relationship. The Synapse action mode (e.g. "rising edge" or "double pulse") specifies the Sig=

nal

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

data condition which triggers the respective Count's count function evaluation to update the count data. It is possible =

for

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

the Synapse action mode to be "none" if a Signal is associate=

d

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

with a Count but does not trigger the count function (e.g. th=

e

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

direction signal line for a Pulse-Direction encoding counter)=

.

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

This component was called "Trigger" in the previous patches. I do not believe "Trigger" was a good name for two main reasons: it could easi=

ly

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

be confused for the existing IIO trigger concept, and most importantl=

y

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 2 lines

it does not convey the connection association aspect of the Count-Signal relationship.

An alternative here would be to use MAP as a number of similar 'connection' type arrangements in the kernel do. It doesn't really imply the 'how' element though so perhaps a new term is indeed better.

Quoted 1 line
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

I settled on the "Synapse" name both due to etymology -- from Greek _sunapsis_ meaning "conjunction" -- as well as a biological analogy:
just as neurons connect and fire communication over synapses, so does=

a

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

Counter Signal connect and fire communication to a Counter Count over=

a

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

Counter Synapse.

Following the same naming convention and analogy, what was previously called trigger_mode is now known as action_mode, named in reference t=

o

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

action potential -- the condition in a neuron which triggers a fire communication over a synapse, just as a Counter Signal condition specified in the action_mode of a Counter Synapse triggers the count function evaluation for a Counter Count.

Counter classes descriptions =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=

=3D=3D=3D=3D=3D

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

The Generic Counter interface is the most general interface for supporting counter devices; if it qualifies as a Counter, then it can=

be

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

represented by the Generic Counter interface. Unfortunately, the flexibility of the interface does result in a more cumbersome integration for driver authors: much of the components must be manual=

ly

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

configured by the author, which can be a tedious task for large and complex counter devices.

To this end, two subclasses of the Generic Counter interface as introduced in this patchset: the Simple Counter interface, and the Quadrature Counter interface. Both of these interfaces inherit the Generic Counter paradigm, and may be seen as extensions to the interf=

ace

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

which restrict the components to a respective specific class of count=

er

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

devices in order to provide a more apt interface for such devices.

Simple Counter
--------------
Simple Counters are devices that count edge pulses on an inpu=

t

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

line (e.g. tally counters).

Since the relationship between Signals and Counts is known to=

be

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

one-to-one, a simple_counter_count structure already contains the associated Signal member for the respective Count. A driv=

er

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

author no longer needs to worry about allocating a separate Signal and Synapse, nor about configuring the association between the respective Count and Signal; the Simple Counter interface abstracts away such details.

Furthermore, since the device type is known, component properties may be further defined and restricted: Count data =

is

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

a signed integer, Signal data "low" and "high" state is set v=

ia

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

enumeration constants, and so are count function and action m=

ode

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines

restricted to well-defined "increase"/"decrease" and "none"/"rising edge"/"falling edge"/"both edges" enumeration constants respectively.

I do wonder a little on whether this is too restrictive to actually represent many devices.

Quoted 1 line
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

Quadrature Counter
------------------
Quadrature Counters are devices that track position based on quadrature pair signals (e.g. rotary encoder counters).

Since the relationship between Signals and Counts is known to=

be

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

a quadrature pair of Signals to each Count, a quad_counter_co=

unt

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

structure already contains the associated Signal members for =

the

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

respective Count. A driver author no longer needs to worry ab=

out

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

allocating separate Signals and Synapses for each quadrature pair, nor about configuring the association between the respective Count and Signals; the Quadrature Counter interfac=

e

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

abstracts away such details.

Furthermore, since the device type is known, component properties may be further defined and restricted: Count data =

is

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

a signed integer, Signal data "low" and "high" state is set v=

ia

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

enumeration constants, and so is count function mode restrict=

ed

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

to well-defined enumeration constants to represent modes such=

as

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line

"pulse-direction" and "quadrature x4" for example.

Pulse direction is definitely not a quadrature counter... Maybe this n=

eeds

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

a rename to dual-signal-counter or similar?

Another classic case here would be increment / decrement counters where a signal is used for each operation (counting items between two light g=

ates

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

- used a lot in tracking products in the production industry).

Quoted 6 lines

Note how driver authors no longer need to interact with Synapses directly when utilizing the Simple Counter and Quadrature Counter interfaces. This should make it easier too for authors to add support since they don't need to fully understand the underlying Counter paradigm in order to take advantage of the interfaces -- just define =

the

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

Counts and Signals, and they're ready to go.

Even more so, the Quadrature Counter interface takes it a step furthe=

r

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

and doesn't require action_modes to be explicitly set -- rather they =

are

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

implicitly determined internally by the system based on the direction and function mode. Abstractions like these should make the Counter interface system as a whole robust enough to handle the diverse class=

es

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

of counter devices out in the real world.

Compilation warnings =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

There are three main compilation warnings which pop for this patchset=

.

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

I've inspected these warnings and none are errors, however they do require some explanation.

* 104-quad-8: warning: enumeration value =E2=80=98QUAD_COUNTER_FUNCTION_PULSE_DIRECTION=E2=80=

=99 not handled in

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

switch

The first warning is rather simple to explain: the QUAD_COUNTER_FUNCTION_PULSE_DIRECTION state is handled by the parent =

if

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines

statement's else condition, so an explicit case condition is not necessary. I can add a default case line to pacify the compiler, but since it would be empty the effort seems frivolous.

Do it anyway and put a comment of /* Should not get here */

Suppressing false warnings is useful from a code maintenance point of v=

iew.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

In some sense as
well, a default case may make the switch logic less clear by implying the possibility of additional cases which are not possible in the context of that code path.

* simple-counter: warning: assignment discards =E2=80=98const=

=E2=80=99 qualifier

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

from pointer target type
* quad-counter: warning: assignment discards =E2=80=98const=

=E2=80=99 qualifier

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

from pointer target type

The second warning comes from the mapping of simple_counter_device_ext/quad_counter_device_ext, simple_counter_count_ext/quad_counter_count_ext, and simple_counter_signal_ext/quad_counter_signal_ext to the internal Counter counter_device_ext, counter_count_ext, and counter_signal_ext structures respectively.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

The priv member of the counter_device_ext, counter_count_ext, or counter_signal_ext is leveraged to pass the respective simple_counter_device_ext/quad_counter_device_ext, simple_counter_count_ext/quad_counter_count_ext, or simple_counter_signal_ext/quad_counter_signal_ext structure to their respective read/write callback. The priv member is generic on purpose=

to

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

allow any desired data to be passed; the supplied read/write callback=

s

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

should know the datatype of the passed-in priv argument so they cast =

it

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

appropriately to access their expected data.

As such, the 'const' qualifier of the structures are thus discarded b=

ut

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

subsequently cast back when the respective registered callback functi=

ons

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

are called. Since this is the intended use case of the priv member --=

to

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 2 lines

generically pass driver data for later recast -- I don't believe this warning needs to be rectified.

All warnings need to be rectified. Sorry but this noise will do two th=

ings:

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

1) Get you a patch every few weeks from someone fixing it.
2) Potentially make real warnings harder to see.

Sometimes we have to play games to work around them, but such is life.

Quoted 3 lines

* generic-counter: warning: passing argument 5 of =E2=80=98counter_attribute_create=E2=80=99 discards =

=E2=80=98const=E2=80=99 qualifier

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

from pointer target type
* generic-counter: warning: passing argument 6 of =E2=80=98counter_attribute_create=E2=80=99 discards =

=E2=80=98const=E2=80=99 qualifier

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

from pointer target type

The third warnings comes from a similar situation to the second warni=

ng:

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

a 'const' argument is passed generically via 'void *' for later recas=

t.

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

In this cast, I decided to create a generic function called counter_attribute_create in order to simplify the sysfs attribute registration code in the generic-counter.c file.

The counter_attribute_create function takes in read and write callbac=

ks,

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

as well as two optional generic data arguments to be stored as 'void =

*'

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

(the component and component_data parameters). Using this setup allow=

s

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

the counter_attribute_create function to be the sole function necessa=

ry

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

to create a desired Generic Counter sysfs attribute: read and write callbacks are passed along with relevant Counter component and data generically, which can be cast back later inside those read and write functions to match the expected datatype.

Using a generic counter_attribute_create function reduces duplicate code, but it does result in many superfluous compilation warnings. I =

can

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

define new attribute_create functions specific to each type of sysfs attribute in order to pacify the warnings, but that seems to be such =

a

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

waste to increase the amount of code with duplications that are unnecessary. What would you recommend; should I attempt to pacify the=

se

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 1 line

warnings or leave them be?

You must fix them I'm afraid.

Quoted 7 lines

Known TODO items
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

Although I've added the interface documentation files with rst file extensions, I still need to familiarize myself with Sphinx markup constructs to take advantage of the language. For example, I've copie=

d

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

verbatim several structure definitions into the documentation directl=

y,

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

but I believe this would be better left dynamically generated by usin=

g

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

the relevant markup syntax. I'll try to clean up the documentation th=

en

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

once I've brushed up on Sphinx.

As noted in a previous patchset version, the signal_write callback should be removed from the interface; there are few if any cases wher=

e

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

it makese sense to have a signal_write callback since Signals are always considered inputs in the context of the Counter paradigm.

I've retained the signal_write callback in this version since I'm uns=

ure

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

how to implement the dummy-counter Signal source. Benjamin Gaignard suggested implementing dummy-counter as a gpio-counter which could us=

e

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

gpio to provide a software quadratic counter. Is this the path I shou=

ld

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line

take?

It would certainly work well and be simple enough for easy understandin=

g.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

Also, it might be a useful driver in it's own right.

Quoted 4 lines

Furthermore, the dummy-counter driver defines its own single platform_device which restricts it to loading only a single instance. I can fix this to allow multiple instances in the next patchset versi=

on

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

-- as suggested, I'll check out industrialio-sw-device.c for referenc=

e.

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

Right now the dummy-counter driver only has example code for the Simp=

le

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

Counter interface. It may be prudent to add example code for the Gene=

ric

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

Counter and Quadrature Counter interfaces too. I think dummy-counter should serve as the reference driver implementation for all the Count=

er

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

interfaces, so that driver authors have an example of how to integrat=

e

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line

the particular interface they desire.

Such a driver is useful, but it doesn't add much if you have another, only slightly more complex real driver that also does the job. Perhaps do them all as gpio based drivers for example?

Quoted 1 line
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

Finally, I only added very basic support for the Quadrature Counter interface in the 104-QUAD-8 driver. It's possible to support all existing IIO Counter sysfs attributes in the 104-QUAD-8 driver via corresponding quad_counter_device_ext, quad_counter_count_ext, and quad_counter_signal_ext structures, such that only the /sys/bus/counter/devices/counterX/ directory needs to be accessed to interact with the 104-QUAD-8 device. I'll try to add support for thos=

e

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

remaining sysfs attributes in the next patchset version.

If I missed anything from the last patchset version review just remin=

d

Quoted 20 lines
Quoted 20 lines
Quoted 20 lines
Quoted 1 line

me again and I'll add it to my TODO list. ;)

You are seriously optimistic if you think we can remember!

Jonathan

Quoted 14 lines

William Breathitt Gray (11):
iio: Introduce the Generic Counter interface
counter: Documentation: Add Generic Counter sysfs documentation
docs: Add Generic Counter interface documentation
counter: Introduce the Simple Counter interface
counter: Documentation: Add Simple Counter sysfs documentation
docs: Add Simple Counter interface documentation
counter: Add dummy counter driver
counter: Introduce the Quadrature Counter interface
counter: Documentation: Add Quadrature Counter sysfs documentation
docs: Add Quadrature Counter interface documentation
counter: 104-quad-8: Add Quadrature Counter interface support

Quoted 14 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
 .../ABI/testing/sysfs-bus-counter-generic-sysfs    |  73 ++
 .../ABI/testing/sysfs-bus-counter-quadrature-sysfs |  76 ++
 .../ABI/testing/sysfs-bus-counter-simple-sysfs     |  61 ++
 Documentation/driver-api/iio/generic-counter.rst   | 434 +++++++++
 Documentation/driver-api/iio/index.rst             |   3 +
 Documentation/driver-api/iio/quad-counter.rst      | 444 +++++++++
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
 Documentation/driver-api/iio/simple-counter.rst    | 393 ++++++++
 MAINTAINERS                                        |   9 +
 drivers/iio/Kconfig                                |   3 +-
 drivers/iio/counter/104-quad-8.c                   | 257 +++++-
 drivers/iio/counter/Kconfig                        |  35 +-
 drivers/iio/counter/Makefile                       |   6 +
 drivers/iio/counter/dummy-counter.c                | 308 +++++++

drivers/iio/counter/generic-counter.c | 992 +++++++++++=

++++++++++

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

drivers/iio/counter/quad-counter.c | 774 +++++++++++=

+++++

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

drivers/iio/counter/simple-counter.c | 734 +++++++++++=

++++

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

include/linux/iio/counter.h | 629 +++++++++++=

++

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
 17 files changed, 5216 insertions(+), 15 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-gener=

ic-sysfs

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-quadr=

ature-sysfs

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-simpl=

e-sysfs

Quoted 15 lines
Quoted 15 lines
Quoted 14 lines
Quoted 9 lines
 create mode 100644 Documentation/driver-api/iio/generic-counter.rst
 create mode 100644 Documentation/driver-api/iio/quad-counter.rst
 create mode 100644 Documentation/driver-api/iio/simple-counter.rst
 create mode 100644 drivers/iio/counter/dummy-counter.c
 create mode 100644 drivers/iio/counter/generic-counter.c
 create mode 100644 drivers/iio/counter/quad-counter.c
 create mode 100644 drivers/iio/counter/simple-counter.c
 create mode 100644 include/linux/iio/counter.h

--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#23 lore raw
Quoted 51 lines · Benjamin Gaignard

2018-01-15 10:02 GMT+01:00 Benjamin Gaignard <[email protected]>:

Quoted 50 lines

2018-01-01 14:04 GMT+01:00 Jonathan Cameron <[email protected]>:

Quoted 31 lines

On Mon, 1 Jan 2018 11:16:30 +0000
Jonathan Cameron <[email protected]> wrote:

Sorry to top post but I just want to add some general comments across the whole series.

1) Basics look good to me. It all fits together well.
2) I'm concerned about the two 'simplified interfaces' for a couple of reasons:
a) They add a lot of code and I'm not convinced the simplifications justify that.
b) They aren't as generically applicable as we might want. For example, it's common for SoC Encoder blocks to operative in both the simple counter mode and the quadrature counter mode. To support that we have (I think) to go back to basics and do it ourselves from the generic counter interface. The TI eQEP IP does these modes for example.

So these simplifications serve two purposes (I think)
1) To enforce interface. This is nice (and I did some similar stuff in IIO for the same reason) but there is so much flexibility in the rest of the interface (from a code point of view) that I'm unsure this is significant.
2) To save on boiler plate. I'm not sure we save that much and that it couldn't mostly be achieved by providing some useful utility functions and standard enums / string arrays for the common cases.

We have to justify a couple of thousand lines of core code. To do that we need to be saving a reasonably multiple more than that in driver code.

The full setup for a generic_counter is not so complex that we need this stuff. Your examples make it all pretty clear what is going on and a couple of clean well commented drivers to act as a baseline for new implementations would get us much of the rest of the way.

Quoted 7 lines

So going well, but this aspect needs some more consideration.

I also think we need at least rough outlines of a few more drivers in here to convince people that there aren't any problems that this is too inflexible to cover. Hopefully an ST one will be forthcoming. If not we can do the exercise off datasheets.

Sorry for the long delay before answering to thread.
I have succesfully implement and test a quadrature encoder driver on stm32 timer part. Some clean up are need but the basic functions like setting the two supported modes (quadX2 or quadX4) supported by my hardware, counting, preset and direction are functional.

I have used the "simplified interface" so my driver is quite simple with only few functions to implement (~300 lines of code).
When this series will be upstream we can convert stm32 drivers to use it.

Quoted 7 lines
Quoted 2 lines

Thanks a lot for this work.
Benjamin

Any news about those patches ?

Regards,
Benjamin

Hi Benjamin,

Sorry for going dark all this time, I'm still incorporating the changes suggested by Jonathan in his review. The biggest change will likely be a reimplementation of the "simple" and "quadrature" API as macros leveraging the "generic" API in order to reduce a lot of redundant code under the hood.

I think I might be comfortable releasing the next revision of the patchset on March 3 or 4, so keep an eye out for it then. :)

William Breathitt Gray

Quoted 463 lines
Quoted 463 lines
Quoted 463 lines

Jonathan

Quoted 458 lines
Quoted 6 lines · On Thu, 14 Dec 2017 15:50:29 -0500 William Breathitt Gray…

Introduction
============

Apologies for going silent these past couple months just to return with a patchset over 3000 lines larger than the last -- I should have been releasing intermediate versions along the way so shame on me!

:) Sometimes it's better to wait until you are moderately happy with it yourself!

Quoted 8 lines

The
Counter system has effectively been rewritten anew, so I believe very little of the code in the previous versions of this patchset remain. However, the Generic Counter paradigm has pretty much remained the same so the theory should be familar. Regardless, I realize I'm dropping off this patchset near the winter holidays so I don't expect a review until well into January -- I'm just releasing this now before I myself head off on an end of year sabbatical.

It's at least a few hours into January so here goes before life gets properly busy again.

Quoted 17 lines

The most significant difference between this version and the previous, as well as part of the reason for the implementation code changes, is the complete separation of the Generic Counter system from IIO. I decided it was improper to build the Generic Counter system on top of IIO core: it was leading to ugly code, convulted hacks, and forced restrictions on the Generic Counter interface in order to appease the architecture of the IIO system. Most importantly, the IIO core code that was leveraged by the Generic Counter was so minor (essentially just the sysfs attribute support) that it did not justify the extensive hoop-jumping performed to make the code work.

So this patchset introduces the Generic Counter interface without the dependence on IIO code. This now gives the Generic Counter system the freedom to aptly represent counter devices without implementation compatibility concerns regarding other high-level subsystems.

Quoted 11 lines

This also makes sense ontologically I believe because whereas the IIO system appears more focused on representing the industrial I/O of a device and their configuration directly, the Generic Counter system is more concerned with the abstract representation of that counter device and the relationships and configurations within which define its operation at a high-level; a counter driver could in theory separately support both the high-level Generic Counter representation of the device as a whole (what are we counting conceptually, how much are we counting, etc.), as well as the low-level IIO representation of the individual inputs and outputs on that device (are the signals differential, do certain signals have current requirements, etc.).

I think there are concepts that over time may blur the lines more but agree with the basic point. I'm just planning to nick all your good ideas if they will improve IIO in turn.

Quoted 30 lines

Overview
========

This patchset may be divided into three main groups:

* Generic Counter
* Simple Counter
* Quadrature Counter

Each group begins with a patch introducing the implementation of the interface system, followed afterwards by documentation patches. I recommend reading through the documentation patches first to familiarize your with the interface itself before jumping into the source code for the implementation.

The Simple Counter and Quadrature Counter groups also have example driver code in the dummy-counter and 104-quad-8 patches respectively. The Simple Counter and Quadrature Counter systems themselves being subclasses of the Generic Counter may serve as example driver code for the Generic Counter interface -- though I may end up adding an explicit Generic Counter example in a later patch to the dummy-counter for easier reference.

Since the Generic Counter system no longer depends on IIO, I moved all Counter related source code to the drivers/iio/counter/ directory to keep everything contained together. In addition, with the IIO Kconfig dependency removed, the COUNTER menu appear now appears at the same level as the IIO menu:

Quoted 7 lines
        -> Device drivers
          -> Counter Support (COUNTER [=m])

I'm not sure if I should move driver/iio/counter/ to driver/counter/ in order to match the Kconfig heirarchy or to keep it where it is to match the legacy IIO counter location established when we first added the 104-QUAD-8 driver.

I would move it out entirely - otherwise things are just confusing. You 'could' sit it in IIO (as in put it under the top level menu option) if you would prefer but I don't thing that really makes sense.

Quoted 16 lines

Paradigm updates
================

The Generic Counter paradigm has essentially remained the same from the previous patch, but I have made some minor updates. In particular, I've finally settled on a naming convention for the core components of a Counter:

COUNT
-----
A Count represents the count data for a set of Signals. A Count has a count function mode (e.g. "increase" or "quadrature x4") which represents the update behavior for the count data. A Count
also has a set of one or more associated Signals.

Quoted 4 lines

This component was called "Value" in the previous patches. I believe "Count" is a more direct name for this data, and it also matches how datasheets and people commonly refer to this information in documentation.

Agreed - better name.

Quoted 24 lines

SIGNAL
------
A Signal represents a counter input data; this is the data that is typically analyzed by the counter to determine the count data. A Signal may be associated to one or more Counts.

The naming for this component has not changed since the previous patches. I believe "Signal" is a fitting enough name for the input data, as well as matching the common nomenclature for existing counter devices.

SYNAPSE
-------
A Synapse represents the association of a Signal with a respective Count. Signal data affects respective Count data, and the Synapse represents this relationship. The Synapse action mode (e.g. "rising edge" or "double pulse") specifies the Signal data condition which triggers the respective Count's count function evaluation to update the count data. It is possible for the Synapse action mode to be "none" if a Signal is associated with a Count but does not trigger the count function (e.g. the direction signal line for a Pulse-Direction encoding counter).

Quoted 5 lines

This component was called "Trigger" in the previous patches. I do not believe "Trigger" was a good name for two main reasons: it could easily be confused for the existing IIO trigger concept, and most importantly it does not convey the connection association aspect of the Count-Signal relationship.

An alternative here would be to use MAP as a number of similar 'connection' type arrangements in the kernel do. It doesn't really imply the 'how' element though so perhaps a new term is indeed better.

Quoted 45 lines

I settled on the "Synapse" name both due to etymology -- from Greek _sunapsis_ meaning "conjunction" -- as well as a biological analogy:
just as neurons connect and fire communication over synapses, so does a Counter Signal connect and fire communication to a Counter Count over a Counter Synapse.

Following the same naming convention and analogy, what was previously called trigger_mode is now known as action_mode, named in reference to action potential -- the condition in a neuron which triggers a fire communication over a synapse, just as a Counter Signal condition specified in the action_mode of a Counter Synapse triggers the count function evaluation for a Counter Count.

Counter classes descriptions
============================

The Generic Counter interface is the most general interface for supporting counter devices; if it qualifies as a Counter, then it can be represented by the Generic Counter interface. Unfortunately, the flexibility of the interface does result in a more cumbersome integration for driver authors: much of the components must be manually configured by the author, which can be a tedious task for large and complex counter devices.

To this end, two subclasses of the Generic Counter interface as introduced in this patchset: the Simple Counter interface, and the Quadrature Counter interface. Both of these interfaces inherit the Generic Counter paradigm, and may be seen as extensions to the interface which restrict the components to a respective specific class of counter devices in order to provide a more apt interface for such devices.

Simple Counter
--------------
Simple Counters are devices that count edge pulses on an input line (e.g. tally counters).

Since the relationship between Signals and Counts is known to be one-to-one, a simple_counter_count structure already contains the associated Signal member for the respective Count. A driver author no longer needs to worry about allocating a separate Signal and Synapse, nor about configuring the association between the respective Count and Signal; the Simple Counter interface abstracts away such details.

Quoted 7 lines

Furthermore, since the device type is known, component properties may be further defined and restricted: Count data is a signed integer, Signal data "low" and "high" state is set via enumeration constants, and so are count function and action mode restricted to well-defined "increase"/"decrease" and "none"/"rising edge"/"falling edge"/"both edges" enumeration constants respectively.

I do wonder a little on whether this is too restrictive to actually represent many devices.

Quoted 15 lines

Quadrature Counter
------------------
Quadrature Counters are devices that track position based on quadrature pair signals (e.g. rotary encoder counters).

Since the relationship between Signals and Counts is known to be a quadrature pair of Signals to each Count, a quad_counter_count structure already contains the associated Signal members for the respective Count. A driver author no longer needs to worry about allocating separate Signals and Synapses for each quadrature pair, nor about configuring the association between the respective Count and Signals; the Quadrature Counter interface abstracts away such details.

Quoted 6 lines

Furthermore, since the device type is known, component properties may be further defined and restricted: Count data is a signed integer, Signal data "low" and "high" state is set via enumeration constants, and so is count function mode restricted to well-defined enumeration constants to represent modes such as "pulse-direction" and "quadrature x4" for example.

Pulse direction is definitely not a quadrature counter... Maybe this needs a rename to dual-signal-counter or similar?

Another classic case here would be increment / decrement counters where a signal is used for each operation (counting items between two light gates
- used a lot in tracking products in the production industry).

Quoted 26 lines

Note how driver authors no longer need to interact with Synapses directly when utilizing the Simple Counter and Quadrature Counter interfaces. This should make it easier too for authors to add support since they don't need to fully understand the underlying Counter paradigm in order to take advantage of the interfaces -- just define the Counts and Signals, and they're ready to go.

Even more so, the Quadrature Counter interface takes it a step further and doesn't require action_modes to be explicitly set -- rather they are implicitly determined internally by the system based on the direction and function mode. Abstractions like these should make the Counter interface system as a whole robust enough to handle the diverse classes of counter devices out in the real world.

Compilation warnings
====================

There are three main compilation warnings which pop for this patchset. I've inspected these warnings and none are errors, however they do require some explanation.

* 104-quad-8: warning: enumeration value ‘QUAD_COUNTER_FUNCTION_PULSE_DIRECTION’ not handled in switch

Quoted 5 lines

The first warning is rather simple to explain: the QUAD_COUNTER_FUNCTION_PULSE_DIRECTION state is handled by the parent if statement's else condition, so an explicit case condition is not necessary. I can add a default case line to pacify the compiler, but since it would be empty the effort seems frivolous.

Do it anyway and put a comment of /* Should not get here */

Suppressing false warnings is useful from a code maintenance point of view.

Quoted 27 lines

In some sense as
well, a default case may make the switch logic less clear by implying the possibility of additional cases which are not possible in the context of that code path.

* simple-counter: warning: assignment discards ‘const’ qualifier from pointer target type
* quad-counter: warning: assignment discards ‘const’ qualifier from pointer target type

The second warning comes from the mapping of simple_counter_device_ext/quad_counter_device_ext, simple_counter_count_ext/quad_counter_count_ext, and simple_counter_signal_ext/quad_counter_signal_ext to the internal Counter counter_device_ext, counter_count_ext, and counter_signal_ext structures respectively.

The priv member of the counter_device_ext, counter_count_ext, or counter_signal_ext is leveraged to pass the respective simple_counter_device_ext/quad_counter_device_ext, simple_counter_count_ext/quad_counter_count_ext, or simple_counter_signal_ext/quad_counter_signal_ext structure to their respective read/write callback. The priv member is generic on purpose to allow any desired data to be passed; the supplied read/write callbacks should know the datatype of the passed-in priv argument so they cast it appropriately to access their expected data.

Quoted 5 lines

As such, the 'const' qualifier of the structures are thus discarded but subsequently cast back when the respective registered callback functions are called. Since this is the intended use case of the priv member -- to generically pass driver data for later recast -- I don't believe this warning needs to be rectified.

All warnings need to be rectified. Sorry but this noise will do two things:
1) Get you a patch every few weeks from someone fixing it.
2) Potentially make real warnings harder to see.

Sometimes we have to play games to work around them, but such is life.

Quoted 23 lines

* generic-counter: warning: passing argument 5 of ‘counter_attribute_create’ discards ‘const’ qualifier from pointer target type
* generic-counter: warning: passing argument 6 of ‘counter_attribute_create’ discards ‘const’ qualifier from pointer target type

The third warnings comes from a similar situation to the second warning:
a 'const' argument is passed generically via 'void *' for later recast. In this cast, I decided to create a generic function called counter_attribute_create in order to simplify the sysfs attribute registration code in the generic-counter.c file.

The counter_attribute_create function takes in read and write callbacks, as well as two optional generic data arguments to be stored as 'void *' (the component and component_data parameters). Using this setup allows the counter_attribute_create function to be the sole function necessary to create a desired Generic Counter sysfs attribute: read and write callbacks are passed along with relevant Counter component and data generically, which can be cast back later inside those read and write functions to match the expected datatype.

Quoted 7 lines

Using a generic counter_attribute_create function reduces duplicate code, but it does result in many superfluous compilation warnings. I can define new attribute_create functions specific to each type of sysfs attribute in order to pacify the warnings, but that seems to be such a waste to increase the amount of code with duplications that are unnecessary. What would you recommend; should I attempt to pacify these warnings or leave them be?

You must fix them I'm afraid.

Quoted 17 lines

Known TODO items
================

Although I've added the interface documentation files with rst file extensions, I still need to familiarize myself with Sphinx markup constructs to take advantage of the language. For example, I've copied verbatim several structure definitions into the documentation directly, but I believe this would be better left dynamically generated by using the relevant markup syntax. I'll try to clean up the documentation then once I've brushed up on Sphinx.

As noted in a previous patchset version, the signal_write callback should be removed from the interface; there are few if any cases where it makese sense to have a signal_write callback since Signals are always considered inputs in the context of the Counter paradigm.

Quoted 5 lines

I've retained the signal_write callback in this version since I'm unsure how to implement the dummy-counter Signal source. Benjamin Gaignard suggested implementing dummy-counter as a gpio-counter which could use gpio to provide a software quadratic counter. Is this the path I should take?

It would certainly work well and be simple enough for easy understanding. Also, it might be a useful driver in it's own right.

Quoted 6 lines

Furthermore, the dummy-counter driver defines its own single platform_device which restricts it to loading only a single instance. I can fix this to allow multiple instances in the next patchset version -- as suggested, I'll check out industrialio-sw-device.c for reference.

Quoted 6 lines

Right now the dummy-counter driver only has example code for the Simple Counter interface. It may be prudent to add example code for the Generic Counter and Quadrature Counter interfaces too. I think dummy-counter should serve as the reference driver implementation for all the Counter interfaces, so that driver authors have an example of how to integrate the particular interface they desire.

Such a driver is useful, but it doesn't add much if you have another, only slightly more complex real driver that also does the job. Perhaps do them all as gpio based drivers for example?

Quoted 10 lines

Finally, I only added very basic support for the Quadrature Counter interface in the 104-QUAD-8 driver. It's possible to support all existing IIO Counter sysfs attributes in the 104-QUAD-8 driver via corresponding quad_counter_device_ext, quad_counter_count_ext, and quad_counter_signal_ext structures, such that only the /sys/bus/counter/devices/counterX/ directory needs to be accessed to interact with the 104-QUAD-8 device. I'll try to add support for those remaining sysfs attributes in the next patchset version.

Quoted 2 lines

If I missed anything from the last patchset version review just remind me again and I'll add it to my TODO list. ;)

You are seriously optimistic if you think we can remember!

Jonathan

Quoted 35 lines

William Breathitt Gray (11):
iio: Introduce the Generic Counter interface
counter: Documentation: Add Generic Counter sysfs documentation
docs: Add Generic Counter interface documentation
counter: Introduce the Simple Counter interface
counter: Documentation: Add Simple Counter sysfs documentation
docs: Add Simple Counter interface documentation
counter: Add dummy counter driver
counter: Introduce the Quadrature Counter interface
counter: Documentation: Add Quadrature Counter sysfs documentation
docs: Add Quadrature Counter interface documentation
counter: 104-quad-8: Add Quadrature Counter interface support

 .../ABI/testing/sysfs-bus-counter-generic-sysfs    |  73 ++
 .../ABI/testing/sysfs-bus-counter-quadrature-sysfs |  76 ++
 .../ABI/testing/sysfs-bus-counter-simple-sysfs     |  61 ++
 Documentation/driver-api/iio/generic-counter.rst   | 434 +++++++++
 Documentation/driver-api/iio/index.rst             |   3 +
 Documentation/driver-api/iio/quad-counter.rst      | 444 +++++++++
 Documentation/driver-api/iio/simple-counter.rst    | 393 ++++++++
 MAINTAINERS                                        |   9 +
 drivers/iio/Kconfig                                |   3 +-
 drivers/iio/counter/104-quad-8.c                   | 257 +++++-
 drivers/iio/counter/Kconfig                        |  35 +-
 drivers/iio/counter/Makefile                       |   6 +
 drivers/iio/counter/dummy-counter.c                | 308 +++++++
 drivers/iio/counter/generic-counter.c              | 992 +++++++++++++++++++++
 drivers/iio/counter/quad-counter.c                 | 774 ++++++++++++++++
 drivers/iio/counter/simple-counter.c               | 734 +++++++++++++++
 include/linux/iio/counter.h                        | 629 +++++++++++++
 17 files changed, 5216 insertions(+), 15 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-generic-sysfs
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-quadrature-sysfs
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-simple-sysfs
Quoted 9 lines
 create mode 100644 Documentation/driver-api/iio/generic-counter.rst
 create mode 100644 Documentation/driver-api/iio/quad-counter.rst
 create mode 100644 Documentation/driver-api/iio/simple-counter.rst
 create mode 100644 drivers/iio/counter/dummy-counter.c
 create mode 100644 drivers/iio/counter/generic-counter.c
 create mode 100644 drivers/iio/counter/quad-counter.c
 create mode 100644 drivers/iio/counter/simple-counter.c
 create mode 100644 include/linux/iio/counter.h

--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#24 lore raw

2018-02-23 14:14 GMT+01:00 William Breathitt Gray <[email protected]>:

Quoted 2 lines · Benjamin Gaignard
Quoted 1 line

2018-01-15 10:02 GMT+01:00 Benjamin Gaignard <[email protected]=

g>:

Quoted 1 line
Quoted 1 line
Quoted 1 line

2018-01-01 14:04 GMT+01:00 Jonathan Cameron <[email protected]=

k>:

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

On Mon, 1 Jan 2018 11:16:30 +0000
Jonathan Cameron <[email protected]> wrote:

Sorry to top post but I just want to add some general comments across the whole series.

1) Basics look good to me. It all fits together well.
2) I'm concerned about the two 'simplified interfaces' for a couple of=

reasons:

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

a) They add a lot of code and I'm not convinced the simplifications ju=

stify that.

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

b) They aren't as generically applicable as we might want. For example=

, it's

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

common for SoC Encoder blocks to operative in both the simple counter =

mode and

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

the quadrature counter mode. To support that we have (I think) to go =

back to

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

basics and do it ourselves from the generic counter interface. The TI=

eQEP

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

IP does these modes for example.

So these simplifications serve two purposes (I think)
1) To enforce interface. This is nice (and I did some similar stuff i=

n IIO

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

for the same reason) but there is so much flexibility in the rest o=

f the

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

interface (from a code point of view) that I'm unsure this is signi=

ficant.

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

2) To save on boiler plate. I'm not sure we save that much and that i=

t couldn't

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

mostly be achieved by providing some useful utility functions and standard enums / string arrays for the common cases.

We have to justify a couple of thousand lines of core code. To do tha=

t we

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

need to be saving a reasonably multiple more than that in driver code.

The full setup for a generic_counter is not so complex that we need th=

is

Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
Quoted 11 lines

stuff. Your examples make it all pretty clear what is going on and a couple of clean well commented drivers to act as a baseline for new implementations would get us much of the rest of the way.

So going well, but this aspect needs some more consideration.

I also think we need at least rough outlines of a few more drivers in here to convince people that there aren't any problems that this is too inflexible to cover. Hopefully an ST one will be forthcoming. If not we can do the exercise off datasheets.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

Sorry for the long delay before answering to thread.
I have succesfully implement and test a quadrature encoder driver on stm32 timer part. Some clean up are need but the basic functions like setting the two supported modes (quadX2 or quadX4) supported by my hardware, counting, preset and direction are functional.

I have used the "simplified interface" so my driver is quite simple wit=

h

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

only few functions to implement (~300 lines of code).
When this series will be upstream we can convert stm32 drivers to use i=

t.

Quoted 11 lines
Quoted 8 lines
Quoted 3 lines

Thanks a lot for this work.
Benjamin

Any news about those patches ?

Regards,
Benjamin

Hi Benjamin,

Quoted 8 lines

Sorry for going dark all this time, I'm still incorporating the changes suggested by Jonathan in his review. The biggest change will likely be a reimplementation of the "simple" and "quadrature" API as macros leveraging the "generic" API in order to reduce a lot of redundant code under the hood.

I think I might be comfortable releasing the next revision of the patchset on March 3 or 4, so keep an eye out for it then. :)

I will, thanks for the update.

Quoted 14 lines

William Breathitt Gray

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines

Jonathan

Quoted 7 lines
Quoted 4 lines · On Thu, 14 Dec 2017 15:50:29 -0500 William Breathitt Gray…

Introduction
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

Apologies for going silent these past couple months just to return =

with

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

a patchset over 3000 lines larger than the last -- I should have be=

en

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line

releasing intermediate versions along the way so shame on me!

:) Sometimes it's better to wait until you are moderately happy with =

it

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

yourself!

Quoted 2 lines

The
Counter system has effectively been rewritten anew, so I believe ve=

ry

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

little of the code in the previous versions of this patchset remain=

.

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

However, the Generic Counter paradigm has pretty much remained the =

same

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

so the theory should be familar. Regardless, I realize I'm dropping=

off

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

this patchset near the winter holidays so I don't expect a review u=

ntil

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

well into January -- I'm just releasing this now before I myself he=

ad

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 1 line

off on an end of year sabbatical.

It's at least a few hours into January so here goes before life gets properly busy again.

Quoted 2 lines

The most significant difference between this version and the previo=

us,

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

as well as part of the reason for the implementation code changes, =

is

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

the complete separation of the Generic Counter system from IIO. I decided it was improper to build the Generic Counter system on top =

of

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

IIO core: it was leading to ugly code, convulted hacks, and forced restrictions on the Generic Counter interface in order to appease t=

he

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

architecture of the IIO system. Most importantly, the IIO core code=

that

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

was leveraged by the Generic Counter was so minor (essentially just=

the

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

sysfs attribute support) that it did not justify the extensive hoop-jumping performed to make the code work.

So this patchset introduces the Generic Counter interface without t=

he

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

dependence on IIO code. This now gives the Generic Counter system t=

he

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

freedom to aptly represent counter devices without implementation compatibility concerns regarding other high-level subsystems.

This also makes sense ontologically I believe because whereas the I=

IO

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

system appears more focused on representing the industrial I/O of a device and their configuration directly, the Generic Counter system=

is

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

more concerned with the abstract representation of that counter dev=

ice

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

and the relationships and configurations within which define its operation at a high-level; a counter driver could in theory separat=

ely

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

support both the high-level Generic Counter representation of the d=

evice

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

as a whole (what are we counting conceptually, how much are we coun=

ting,

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

etc.), as well as the low-level IIO representation of the individua=

l

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 2 lines

inputs and outputs on that device (are the signals differential, do certain signals have current requirements, etc.).

I think there are concepts that over time may blur the lines more but agree with the basic point. I'm just planning to nick all your good ideas if they will improve IIO in turn.

Quoted 4 lines

Overview
=3D=3D=3D=3D=3D=3D=3D=3D

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

This patchset may be divided into three main groups:

* Generic Counter
* Simple Counter
* Quadrature Counter

Each group begins with a patch introducing the implementation of th=

e

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

interface system, followed afterwards by documentation patches. I recommend reading through the documentation patches first to famili=

arize

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

your with the interface itself before jumping into the source code =

for

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

the implementation.

The Simple Counter and Quadrature Counter groups also have example driver code in the dummy-counter and 104-quad-8 patches respectivel=

y.

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

The Simple Counter and Quadrature Counter systems themselves being subclasses of the Generic Counter may serve as example driver code =

for

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

the Generic Counter interface -- though I may end up adding an expl=

icit

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

Generic Counter example in a later patch to the dummy-counter for e=

asier

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

reference.

Since the Generic Counter system no longer depends on IIO, I moved =

all

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

Counter related source code to the drivers/iio/counter/ directory t=

o

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

keep everything contained together. In addition, with the IIO Kconf=

ig

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

dependency removed, the COUNTER menu appear now appears at the same level as the IIO menu:

        -> Device drivers
          -> Counter Support (COUNTER [=3Dm])

I'm not sure if I should move driver/iio/counter/ to driver/counter=

/ in

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

order to match the Kconfig heirarchy or to keep it where it is to m=

atch

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines

the legacy IIO counter location established when we first added the 104-QUAD-8 driver.

I would move it out entirely - otherwise things are just confusing. You 'could' sit it in IIO (as in put it under the top level menu opti=

on)

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

if you would prefer but I don't thing that really makes sense.

Quoted 5 lines

Paradigm updates
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

The Generic Counter paradigm has essentially remained the same from=

the

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

previous patch, but I have made some minor updates. In particular, =

I've

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

finally settled on a naming convention for the core components of a Counter:

COUNT
-----
A Count represents the count data for a set of Signals. A C=

ount

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

has a count function mode (e.g. "increase" or "quadrature x=

4")

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

which represents the update behavior for the count data. A =

Count

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

also has a set of one or more associated Signals.

This component was called "Value" in the previous patches. I believ=

e

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

"Count" is a more direct name for this data, and it also matches ho=

w

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 2 lines

datasheets and people commonly refer to this information in documentation.

Agreed - better name.

Quoted 4 lines

SIGNAL
------
A Signal represents a counter input data; this is the data =

that

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

is typically analyzed by the counter to determine the count data. A Signal may be associated to one or more Counts.

The naming for this component has not changed since the previous patches. I believe "Signal" is a fitting enough name for the input data, as well as matching the common nomenclature for existing coun=

ter

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

devices.

SYNAPSE
-------
A Synapse represents the association of a Signal with a respective Count. Signal data affects respective Count data=

, and

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

the Synapse represents this relationship. The Synapse actio=

n

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

mode (e.g. "rising edge" or "double pulse") specifies the S=

ignal

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

data condition which triggers the respective Count's count function evaluation to update the count data. It is possibl=

e for

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

the Synapse action mode to be "none" if a Signal is associa=

ted

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

with a Count but does not trigger the count function (e.g. =

the

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

direction signal line for a Pulse-Direction encoding counte=

r).

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

This component was called "Trigger" in the previous patches. I do n=

ot

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

believe "Trigger" was a good name for two main reasons: it could ea=

sily

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

be confused for the existing IIO trigger concept, and most importan=

tly

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 2 lines

it does not convey the connection association aspect of the Count-Signal relationship.

An alternative here would be to use MAP as a number of similar 'connection' type arrangements in the kernel do. It doesn't really imply the 'how' element though so perhaps a new term is indeed better=

.

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

I settled on the "Synapse" name both due to etymology -- from Greek _sunapsis_ meaning "conjunction" -- as well as a biological analogy=

:

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

just as neurons connect and fire communication over synapses, so do=

es a

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

Counter Signal connect and fire communication to a Counter Count ov=

er a

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

Counter Synapse.

Following the same naming convention and analogy, what was previous=

ly

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

called trigger_mode is now known as action_mode, named in reference=

to

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

action potential -- the condition in a neuron which triggers a fire communication over a synapse, just as a Counter Signal condition specified in the action_mode of a Counter Synapse triggers the coun=

t

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

function evaluation for a Counter Count.

Counter classes descriptions =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=

=3D=3D=3D=3D=3D=3D

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

The Generic Counter interface is the most general interface for supporting counter devices; if it qualifies as a Counter, then it c=

an be

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

represented by the Generic Counter interface. Unfortunately, the flexibility of the interface does result in a more cumbersome integration for driver authors: much of the components must be manu=

ally

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

configured by the author, which can be a tedious task for large and complex counter devices.

To this end, two subclasses of the Generic Counter interface as introduced in this patchset: the Simple Counter interface, and the Quadrature Counter interface. Both of these interfaces inherit the Generic Counter paradigm, and may be seen as extensions to the inte=

rface

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

which restrict the components to a respective specific class of cou=

nter

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

devices in order to provide a more apt interface for such devices.

Simple Counter
--------------
Simple Counters are devices that count edge pulses on an in=

put

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

line (e.g. tally counters).

Since the relationship between Signals and Counts is known =

to be

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

one-to-one, a simple_counter_count structure already contai=

ns

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

the associated Signal member for the respective Count. A dr=

iver

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

author no longer needs to worry about allocating a separate Signal and Synapse, nor about configuring the association between the respective Count and Signal; the Simple Counter interface abstracts away such details.

Furthermore, since the device type is known, component properties may be further defined and restricted: Count dat=

a is

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

a signed integer, Signal data "low" and "high" state is set=

via

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

enumeration constants, and so are count function and action=

mode

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

restricted to well-defined "increase"/"decrease" and "none"/"rising edge"/"falling edge"/"both edges" enumeratio=

n

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 1 line

constants respectively.

I do wonder a little on whether this is too restrictive to actually represent many devices.

Quoted 4 lines

Quadrature Counter
------------------
Quadrature Counters are devices that track position based o=

n

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

quadrature pair signals (e.g. rotary encoder counters).

Since the relationship between Signals and Counts is known =

to be

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

a quadrature pair of Signals to each Count, a quad_counter_=

count

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

structure already contains the associated Signal members fo=

r the

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

respective Count. A driver author no longer needs to worry =

about

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

allocating separate Signals and Synapses for each quadratur=

e

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

pair, nor about configuring the association between the respective Count and Signals; the Quadrature Counter interf=

ace

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

abstracts away such details.

Furthermore, since the device type is known, component properties may be further defined and restricted: Count dat=

a is

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

a signed integer, Signal data "low" and "high" state is set=

via

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

enumeration constants, and so is count function mode restri=

cted

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

to well-defined enumeration constants to represent modes su=

ch as

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line

"pulse-direction" and "quadrature x4" for example.

Pulse direction is definitely not a quadrature counter... Maybe this=

needs

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

a rename to dual-signal-counter or similar?

Another classic case here would be increment / decrement counters whe=

re

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

a signal is used for each operation (counting items between two light=

gates

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

- used a lot in tracking products in the production industry).

Quoted 4 lines

Note how driver authors no longer need to interact with Synapses directly when utilizing the Simple Counter and Quadrature Counter interfaces. This should make it easier too for authors to add suppo=

rt

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

since they don't need to fully understand the underlying Counter paradigm in order to take advantage of the interfaces -- just defin=

e the

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

Counts and Signals, and they're ready to go.

Even more so, the Quadrature Counter interface takes it a step furt=

her

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

and doesn't require action_modes to be explicitly set -- rather the=

y are

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

implicitly determined internally by the system based on the directi=

on

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

and function mode. Abstractions like these should make the Counter interface system as a whole robust enough to handle the diverse cla=

sses

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

of counter devices out in the real world.

Compilation warnings =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

There are three main compilation warnings which pop for this patchs=

et.

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

I've inspected these warnings and none are errors, however they do require some explanation.

* 104-quad-8: warning: enumeration value =E2=80=98QUAD_COUNTER_FUNCTION_PULSE_DIRECTION=E2=

=80=99 not handled in

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

switch

The first warning is rather simple to explain: the QUAD_COUNTER_FUNCTION_PULSE_DIRECTION state is handled by the paren=

t if

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

statement's else condition, so an explicit case condition is not necessary. I can add a default case line to pacify the compiler, bu=

t

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line

since it would be empty the effort seems frivolous.

Do it anyway and put a comment of /* Should not get here */

Suppressing false warnings is useful from a code maintenance point of=

view.

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

In some sense as
well, a default case may make the switch logic less clear by implyi=

ng

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

the possibility of additional cases which are not possible in the context of that code path.

* simple-counter: warning: assignment discards =E2=80=98con=

st=E2=80=99 qualifier

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

from pointer target type
* quad-counter: warning: assignment discards =E2=80=98const=

=E2=80=99 qualifier

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

from pointer target type

The second warning comes from the mapping of simple_counter_device_ext/quad_counter_device_ext, simple_counter_count_ext/quad_counter_count_ext, and simple_counter_signal_ext/quad_counter_signal_ext to the internal Counter counter_device_ext, counter_count_ext, and counter_signal_e=

xt

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

structures respectively.

The priv member of the counter_device_ext, counter_count_ext, or counter_signal_ext is leveraged to pass the respective simple_counter_device_ext/quad_counter_device_ext, simple_counter_count_ext/quad_counter_count_ext, or simple_counter_signal_ext/quad_counter_signal_ext structure to thei=

r

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

respective read/write callback. The priv member is generic on purpo=

se to

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

allow any desired data to be passed; the supplied read/write callba=

cks

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

should know the datatype of the passed-in priv argument so they cas=

t it

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

appropriately to access their expected data.

As such, the 'const' qualifier of the structures are thus discarded=

but

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

subsequently cast back when the respective registered callback func=

tions

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

are called. Since this is the intended use case of the priv member =

-- to

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

generically pass driver data for later recast -- I don't believe th=

is

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line

warning needs to be rectified.

All warnings need to be rectified. Sorry but this noise will do two =

things:

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

1) Get you a patch every few weeks from someone fixing it.
2) Potentially make real warnings harder to see.

Sometimes we have to play games to work around them, but such is life=

.

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

* generic-counter: warning: passing argument 5 of =E2=80=98counter_attribute_create=E2=80=99 discards=

=E2=80=98const=E2=80=99 qualifier

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

from pointer target type
* generic-counter: warning: passing argument 6 of =E2=80=98counter_attribute_create=E2=80=99 discards=

=E2=80=98const=E2=80=99 qualifier

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

from pointer target type

The third warnings comes from a similar situation to the second war=

ning:

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

a 'const' argument is passed generically via 'void *' for later rec=

ast.

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

In this cast, I decided to create a generic function called counter_attribute_create in order to simplify the sysfs attribute registration code in the generic-counter.c file.

The counter_attribute_create function takes in read and write callb=

acks,

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

as well as two optional generic data arguments to be stored as 'voi=

d *'

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

(the component and component_data parameters). Using this setup all=

ows

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

the counter_attribute_create function to be the sole function neces=

sary

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

to create a desired Generic Counter sysfs attribute: read and write callbacks are passed along with relevant Counter component and data generically, which can be cast back later inside those read and wri=

te

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

functions to match the expected datatype.

Using a generic counter_attribute_create function reduces duplicate code, but it does result in many superfluous compilation warnings. =

I can

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

define new attribute_create functions specific to each type of sysf=

s

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

attribute in order to pacify the warnings, but that seems to be suc=

h a

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

waste to increase the amount of code with duplications that are unnecessary. What would you recommend; should I attempt to pacify t=

hese

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 1 line

warnings or leave them be?

You must fix them I'm afraid.

Quoted 7 lines

Known TODO items
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

Although I've added the interface documentation files with rst file extensions, I still need to familiarize myself with Sphinx markup constructs to take advantage of the language. For example, I've cop=

ied

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

verbatim several structure definitions into the documentation direc=

tly,

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

but I believe this would be better left dynamically generated by us=

ing

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

the relevant markup syntax. I'll try to clean up the documentation =

then

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

once I've brushed up on Sphinx.

As noted in a previous patchset version, the signal_write callback should be removed from the interface; there are few if any cases wh=

ere

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

it makese sense to have a signal_write callback since Signals are always considered inputs in the context of the Counter paradigm.

I've retained the signal_write callback in this version since I'm u=

nsure

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

how to implement the dummy-counter Signal source. Benjamin Gaignard suggested implementing dummy-counter as a gpio-counter which could =

use

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

gpio to provide a software quadratic counter. Is this the path I sh=

ould

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line

take?

It would certainly work well and be simple enough for easy understand=

ing.

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

Also, it might be a useful driver in it's own right.

Quoted 3 lines

Furthermore, the dummy-counter driver defines its own single platform_device which restricts it to loading only a single instanc=

e.

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

I can fix this to allow multiple instances in the next patchset ver=

sion

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

-- as suggested, I'll check out industrialio-sw-device.c for refere=

nce.

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

Right now the dummy-counter driver only has example code for the Si=

mple

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

Counter interface. It may be prudent to add example code for the Ge=

neric

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

Counter and Quadrature Counter interfaces too. I think dummy-counte=

r

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

should serve as the reference driver implementation for all the Cou=

nter

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

interfaces, so that driver authors have an example of how to integr=

ate

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line

the particular interface they desire.

Such a driver is useful, but it doesn't add much if you have another, only slightly more complex real driver that also does the job. Perhaps do them all as gpio based drivers for example?

Quoted 1 line
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

Finally, I only added very basic support for the Quadrature Counter interface in the 104-QUAD-8 driver. It's possible to support all existing IIO Counter sysfs attributes in the 104-QUAD-8 driver via corresponding quad_counter_device_ext, quad_counter_count_ext, and quad_counter_signal_ext structures, such that only the /sys/bus/counter/devices/counterX/ directory needs to be accessed t=

o

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

interact with the 104-QUAD-8 device. I'll try to add support for th=

ose

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

remaining sysfs attributes in the next patchset version.

If I missed anything from the last patchset version review just rem=

ind

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 1 line

me again and I'll add it to my TODO list. ;)

You are seriously optimistic if you think we can remember!

Jonathan

Quoted 1 line
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines

William Breathitt Gray (11):
iio: Introduce the Generic Counter interface
counter: Documentation: Add Generic Counter sysfs documentation
docs: Add Generic Counter interface documentation
counter: Introduce the Simple Counter interface
counter: Documentation: Add Simple Counter sysfs documentation
docs: Add Simple Counter interface documentation
counter: Add dummy counter driver
counter: Introduce the Quadrature Counter interface
counter: Documentation: Add Quadrature Counter sysfs documentatio=

n

Quoted 17 lines
Quoted 17 lines
Quoted 17 lines
Quoted 17 lines
Quoted 17 lines
Quoted 16 lines

docs: Add Quadrature Counter interface documentation
counter: 104-quad-8: Add Quadrature Counter interface support

 .../ABI/testing/sysfs-bus-counter-generic-sysfs    |  73 ++
 .../ABI/testing/sysfs-bus-counter-quadrature-sysfs |  76 ++
 .../ABI/testing/sysfs-bus-counter-simple-sysfs     |  61 ++
 Documentation/driver-api/iio/generic-counter.rst   | 434 +++++++++
 Documentation/driver-api/iio/index.rst             |   3 +
 Documentation/driver-api/iio/quad-counter.rst      | 444 +++++++++
 Documentation/driver-api/iio/simple-counter.rst    | 393 ++++++++
 MAINTAINERS                                        |   9 +
 drivers/iio/Kconfig                                |   3 +-
 drivers/iio/counter/104-quad-8.c                   | 257 +++++-
 drivers/iio/counter/Kconfig                        |  35 +-
 drivers/iio/counter/Makefile                       |   6 +
 drivers/iio/counter/dummy-counter.c                | 308 +++++++
Quoted 1 line

drivers/iio/counter/generic-counter.c | 992 +++++++++=

++++++++++++

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

drivers/iio/counter/quad-counter.c | 774 +++++++++=

+++++++

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

drivers/iio/counter/simple-counter.c | 734 +++++++++=

++++++

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

include/linux/iio/counter.h | 629 +++++++++=

++++

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
 17 files changed, 5216 insertions(+), 15 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-gen=

eric-sysfs

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-qua=

drature-sysfs

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
 create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-sim=

ple-sysfs

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
 create mode 100644 Documentation/driver-api/iio/generic-counter.rs=

t

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 8 lines
 create mode 100644 Documentation/driver-api/iio/quad-counter.rst
 create mode 100644 Documentation/driver-api/iio/simple-counter.rst
 create mode 100644 drivers/iio/counter/dummy-counter.c
 create mode 100644 drivers/iio/counter/generic-counter.c
 create mode 100644 drivers/iio/counter/quad-counter.c
 create mode 100644 drivers/iio/counter/simple-counter.c
 create mode 100644 include/linux/iio/counter.h

--
To unsubscribe from this list: send the line "unsubscribe linux-iio" =

in

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 2 lines

the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html