From: William Breathitt Gray <hidden> Date: 2021-03-19 11:01:47
Changes in v10:
- Use sysfs_emit_at() in enums_available_show() and
strs_available_show() in order to concatenate list of strings
- Use sprintf() in counter_comp_id_show(); only printing an size_t so
there is no risk of exceeding PAGE_SIZE
Note that this revision is based on top of 3 prerequisite patches:
* counter: stm32-timer-cnt: fix ceiling miss-alignment with reload register
* counter: stm32-timer-cnt: fix ceiling write max value
* counter: stm32-timer-cnt: Report count function when SLAVE_MODE_DISABLED
I pulled out a lot of bits and pieces to their own patches; hopefully
that makes reviewing this patchset much simpler than before. This
patchset is also available on my personal public git repo for anyone who
wants a quick way to clone:
https://gitlab.com/vilhelmgray/iio/-/tree/counter_chrdev_v10
The patches preceding "counter: Internalize sysfs interface code" are
primarily cleanup and fixes that can be picked up and applied now to the
IIO tree if so desired. The "counter: Internalize sysfs interface code"
patch as well may be considered for pickup because it is relatively safe
and makes no changes to the userspace interface.
To summarize the main points of this patchset: there are no changes to
the existing Counter sysfs userspace interface; a Counter character
device interface is introduced that allows Counter events and associated
data to be read() by userspace; the events_configure() and
watch_validate() driver callbacks are introduced to support Counter
events; and IRQ support is added to the 104-QUAD-8 driver, serving as an
example of how to support the new Counter events functionality.
Something that should still be discussed: should the struct
counter_event "status" member be 8 bits or 32 bits wide? This member
will provide the return status (system error number) of an event
operation.
William Breathitt Gray (33):
docs: counter: Consolidate Counter sysfs attributes documentation
docs: counter: Fix spelling
counter: 104-quad-8: Remove pointless comment
counter: 104-quad-8: Return error when invalid mode during
ceiling_write
counter: 104-quad-8: Annotate hardware config module parameter
counter: 104-quad-8: Add const qualifiers for
quad8_preset_register_set
counter: 104-quad-8: Add const qualifier for functions_list array
counter: interrupt-cnt: Add const qualifier for functions_list array
counter: microchip-tcb-capture: Add const qualifier for functions_list
array
counter: stm32-lptimer-cnt: Add const qualifier for functions_list
array
counter: stm32-timer-cnt: Add const qualifier for functions_list array
counter: 104-quad-8: Add const qualifier for actions_list array
counter: ftm-quaddec: Add const qualifier for actions_list array
counter: interrupt-cnt: Add const qualifier for actions_list array
counter: microchip-tcb-capture: Add const qualifier for actions_list
array
counter: stm32-lptimer-cnt: Add const qualifier for actions_list array
counter: stm32-timer-cnt: Add const qualifier for actions_list array
counter: Return error code on invalid modes
counter: Standardize to ERANGE for limit exceeded errors
counter: Rename counter_signal_value to counter_signal_level
counter: Rename counter_count_function to counter_function
counter: Internalize sysfs interface code
counter: Update counter.h comments to reflect sysfs internalization
docs: counter: Update to reflect sysfs internalization
counter: Move counter enums to uapi header
counter: Add character device interface
docs: counter: Document character device interface
tools/counter: Create Counter tools
counter: Implement signalZ_action_component_id sysfs attribute
counter: Implement *_component_id sysfs attributes
counter: Implement events_queue_size sysfs attribute
counter: 104-quad-8: Replace mutex with spinlock
counter: 104-quad-8: Add IRQ support for the ACCES 104-QUAD-8
Documentation/ABI/testing/sysfs-bus-counter | 112 +-
.../ABI/testing/sysfs-bus-counter-104-quad-8 | 61 -
.../ABI/testing/sysfs-bus-counter-ftm-quaddec | 16 -
Documentation/driver-api/generic-counter.rst | 368 +++-
.../userspace-api/ioctl/ioctl-number.rst | 1 +
MAINTAINERS | 7 +-
drivers/counter/104-quad-8.c | 739 ++++----
drivers/counter/Kconfig | 6 +-
drivers/counter/Makefile | 1 +
drivers/counter/counter-chrdev.c | 486 ++++++
drivers/counter/counter-chrdev.h | 14 +
drivers/counter/counter-core.c | 192 +++
drivers/counter/counter-sysfs.c | 953 +++++++++++
drivers/counter/counter-sysfs.h | 13 +
drivers/counter/counter.c | 1496 -----------------
drivers/counter/ftm-quaddec.c | 61 +-
drivers/counter/interrupt-cnt.c | 75 +-
drivers/counter/microchip-tcb-capture.c | 105 +-
drivers/counter/stm32-lptimer-cnt.c | 176 +-
drivers/counter/stm32-timer-cnt.c | 149 +-
drivers/counter/ti-eqep.c | 221 +--
include/linux/counter.h | 716 ++++----
include/linux/counter_enum.h | 45 -
include/uapi/linux/counter.h | 133 ++
tools/Makefile | 13 +-
tools/counter/Build | 1 +
tools/counter/Makefile | 53 +
tools/counter/counter_example.c | 95 ++
28 files changed, 3522 insertions(+), 2786 deletions(-)
delete mode 100644 Documentation/ABI/testing/sysfs-bus-counter-104-quad-8
delete mode 100644 Documentation/ABI/testing/sysfs-bus-counter-ftm-quaddec
create mode 100644 drivers/counter/counter-chrdev.c
create mode 100644 drivers/counter/counter-chrdev.h
create mode 100644 drivers/counter/counter-core.c
create mode 100644 drivers/counter/counter-sysfs.c
create mode 100644 drivers/counter/counter-sysfs.h
delete mode 100644 drivers/counter/counter.c
delete mode 100644 include/linux/counter_enum.h
create mode 100644 include/uapi/linux/counter.h
create mode 100644 tools/counter/Build
create mode 100644 tools/counter/Makefile
create mode 100644 tools/counter/counter_example.c
base-commit: 69333b92c35cdd6cdfc90c4f5daa418cfeb40213
prerequisite-patch-id: 41fda3a386861edad110c644567fad373a5a175e
prerequisite-patch-id: c6c2ab3173f5a0136d1e9b7b96ccd115fa35d66e
prerequisite-patch-id: 7e3cd78924d79890b690f3029e0d4f5b3902a73c
--
2.30.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
@@ -154,6 +155,15 @@ Description: Count Y. If possible, this should match the name of the respective channel as it appears in the device datasheet.+What: /sys/bus/counter/devices/counterX/countY/prescaler+KernelVersion: 5.2+Contact: linux-iio@vger.kernel.org+Description:+ Configure the prescaler value associated with Count Y.+ On the FlexTimer, the counter clock source passes through a+ prescaler (i.e. a counter). This acts like a clock+ divider.+ What: /sys/bus/counter/devices/counterX/countY/preset KernelVersion: 5.2 Contact: linux-iio@vger.kernel.org
@@ -215,11 +225,45 @@ Description: Read-only attribute that indicates the total number of Signals belonging to the Counter.-What: /sys/bus/counter/devices/counterX/signalY/signal+What: /sys/bus/counter/devices/counterX/signalY/cable_fault+KernelVersion: 5.7+Contact: linux-iio@vger.kernel.org+Description:+ Read-only attribute that indicates whether a differential+ encoder cable fault (not connected or loose wires) is detected+ for the respective channel of Signal Y. Valid attribute values+ are boolean. Detection must first be enabled via the+ corresponding cable_fault_enable attribute.++What: /sys/bus/counter/devices/counterX/signalY/cable_fault_enable+KernelVersion: 5.7+Contact: linux-iio@vger.kernel.org+Description:+ Whether detection of differential encoder cable faults for the+ respective channel of Signal Y is enabled. Valid attribute+ values are boolean.++What: /sys/bus/counter/devices/counterX/signalY/filter_clock_prescaler+KernelVersion: 5.7+Contact: linux-iio@vger.kernel.org+Description:+ Filter clock factor for input Signal Y. This prescaler value+ affects the inputs of both quadrature pair signals.++What: /sys/bus/counter/devices/counterX/signalY/index_polarity KernelVersion: 5.2 Contact: linux-iio@vger.kernel.org Description:- Signal data of Signal Y represented as a string.+ Active level of index input Signal Y; irrelevant in+ non-synchronous load mode.++What: /sys/bus/counter/devices/counterX/signalY/index_polarity_available+What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode_available+KernelVersion: 5.2+Contact: linux-iio@vger.kernel.org+Description:+ Discrete set of available values for the respective Signal Y+ configuration are listed in this file. What: /sys/bus/counter/devices/counterX/signalY/name KernelVersion: 5.2
@@ -228,3 +272,31 @@ Description: Read-only attribute that indicates the device-specific name of Signal Y. If possible, this should match the name of the respective signal as it appears in the device datasheet.++What: /sys/bus/counter/devices/counterX/signalY/signal+KernelVersion: 5.2+Contact: linux-iio@vger.kernel.org+Description:+ Signal data of Signal Y represented as a string.++What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode+KernelVersion: 5.2+Contact: linux-iio@vger.kernel.org+Description:+ Configure the counter associated with Signal Y for+ non-synchronous or synchronous load mode. Synchronous load mode+ cannot be selected in non-quadrature (Pulse-Direction) clock+ mode.++ non-synchronous:+ A logic low level is the active level at this index+ input. The index function (as enabled via preset_enable)+ is performed directly on the active level of the index+ input.++ synchronous:+ Intended for interfacing with encoder Index output in+ quadrature clock mode. The active level is configured+ via index_polarity. The index function (as enabled via+ preset_enable) is performed synchronously with the+ quadrature clock on the active level of the index input.
@@ -1,61 +0,0 @@-What: /sys/bus/counter/devices/counterX/signalY/cable_fault-KernelVersion: 5.7-Contact: linux-iio@vger.kernel.org-Description:- Read-only attribute that indicates whether a differential- encoder cable fault (not connected or loose wires) is detected- for the respective channel of Signal Y. Valid attribute values- are boolean. Detection must first be enabled via the- corresponding cable_fault_enable attribute.--What: /sys/bus/counter/devices/counterX/signalY/cable_fault_enable-KernelVersion: 5.7-Contact: linux-iio@vger.kernel.org-Description:- Whether detection of differential encoder cable faults for the- respective channel of Signal Y is enabled. Valid attribute- values are boolean.--What: /sys/bus/counter/devices/counterX/signalY/filter_clock_prescaler-KernelVersion: 5.7-Contact: linux-iio@vger.kernel.org-Description:- Filter clock factor for input Signal Y. This prescaler value- affects the inputs of both quadrature pair signals.--What: /sys/bus/counter/devices/counterX/signalY/index_polarity-KernelVersion: 5.2-Contact: linux-iio@vger.kernel.org-Description:- Active level of index input Signal Y; irrelevant in- non-synchronous load mode.--What: /sys/bus/counter/devices/counterX/signalY/index_polarity_available-What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode_available-KernelVersion: 5.2-Contact: linux-iio@vger.kernel.org-Description:- Discrete set of available values for the respective Signal Y- configuration are listed in this file.--What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode-KernelVersion: 5.2-Contact: linux-iio@vger.kernel.org-Description:- Configure the counter associated with Signal Y for- non-synchronous or synchronous load mode. Synchronous load mode- cannot be selected in non-quadrature (Pulse-Direction) clock- mode.-- non-synchronous:- A logic low level is the active level at this index- input. The index function (as enabled via preset_enable)- is performed directly on the active level of the index- input.-- synchronous:- Intended for interfacing with encoder Index output in- quadrature clock mode. The active level is configured- via index_polarity. The index function (as enabled via- preset_enable) is performed synchronously with the- quadrature clock on the active level of the index input.
@@ -1,16 +0,0 @@-What: /sys/bus/counter/devices/counterX/countY/prescaler_available-KernelVersion: 5.2-Contact: linux-iio@vger.kernel.org-Description:- Discrete set of available values for the respective Count Y- configuration are listed in this file. Values are delimited by- newline characters.--What: /sys/bus/counter/devices/counterX/countY/prescaler-KernelVersion: 5.2-Contact: linux-iio@vger.kernel.org-Description:- Configure the prescaler value associated with Count Y.- On the FlexTimer, the counter clock source passes through a- prescaler (i.e. a counter). This acts like a clock- divider.
@@ -307,7 +307,7 @@ Determining the type of extension to create is a matter of scope.* Device extensions are attributes that expose information/control non-specific to a particular Count or Signal. This is where you would- put your global features or other miscellanous functionality.+ put your global features or other miscellaneous functionality. For example, if your device has an overtemp sensor, you can report the chip overheated via a device extension called "error_overtemp":
--
2.30.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:02:22
It is obvious that devm_counter_register() is used to register a Counter
device, so a comment stating such is pointless here.
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 1 -
1 file changed, 1 deletion(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:02:22
The 104-QUAD-8 only has two count modes where a ceiling value makes
sense: Range Limit and Modulo-N. Outside of these two modes, setting a
ceiling value is an invalid operation -- so let's report it as such by
returning -EINVAL.
Fixes: fc069262261c ("counter: 104-quad-8: Add lock guards - generic interface")
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:02:22
When the kernel is running in secure boot mode, we lock down the kernel to
prevent userspace from modifying the running kernel image. Whilst this
includes prohibiting access to things like /dev/mem, it must also prevent
access by means of configuring driver modules in such a way as to cause a
device to access or modify the kernel image.
To this end, annotate module_param* statements that refer to hardware
configuration and indicate for future reference what type of parameter they
specify. The parameter parser in the core sees this information and can
skip such parameters with an error message if the kernel is locked down.
The module initialisation then runs as normal, but just sees whatever the
default values for those parameters is.
Note that we do still need to do the module initialisation because some
drivers have viable defaults set in case parameters aren't specified and
some drivers support automatic configuration (e.g. PNP or PCI) in addition
to manually coded parameters.
This patch annotates the 104-QUAD-8 driver.
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:02:22
Add some safety by qualifying the quad8_preset_register_set() function
parameters as const.
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:02:22
The struct counter_count functions_list member expects a const enum
counter_count_function array. This patch adds the const qualifier to the
quad8_count_functions_list to match functions_list.
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:02:22
The struct counter_count functions_list member expects a const enum
counter_count_function array. This patch adds the const qualifier to the
interrupt__cnt_functions to match functions_list.
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/interrupt-cnt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:02:51
The struct counter_count functions_list member expects a const enum
counter_count_function array. This patch adds the const qualifier to the
mchp_tc_count_functions to match functions_list.
Cc: Kamel Bouhara <kamel.bouhara@bootlin.com>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/microchip-tcb-capture.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:02:54
The struct counter_count functions_list member expects a const enum
counter_count_function array. This patch adds the const qualifier to the
stm32_lptim_cnt_functions to match functions_list.
Cc: Fabrice Gasnier <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/stm32-lptimer-cnt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:02:54
The struct counter_synapse actions_list member expects a const enum
counter_synapse_action array. This patch adds the const qualifier to the
quad8_index_actions_list and quad8_synapse_actions_list to match
actions_list.
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:02:54
The struct counter_synapse actions_list member expects a const enum
counter_synapse_action array. This patch adds the const qualifier to the
ftm_quaddec_synapse_actions to match actions_list.
Cc: Patrick Havelange <patrick.havelange@essensium.com>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/ftm-quaddec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:02:54
The struct counter_count functions_list member expects a const enum
counter_count_function array. This patch adds the const qualifier to the
stm32_count_functions to match functions_list.
Cc: Fabrice Gasnier <redacted>
Cc: Benjamin Gaignard <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/stm32-timer-cnt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:02:54
The struct counter_synapse actions_list member expects a const enum
counter_synapse_action array. This patch adds the const qualifier to the
interrupt_cnt_synapse_actionss to match actions_list.
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/interrupt-cnt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:03:24
The struct counter_synapse actions_list member expects a const enum
counter_synapse_action array. This patch adds the const qualifier to the
mchp_tc_synapse_actions to match actions_list.
Cc: Kamel Bouhara <kamel.bouhara@bootlin.com>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/microchip-tcb-capture.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:03:25
The struct counter_synapse actions_list member expects a const enum
counter_synapse_action array. This patch adds the const qualifier to the
stm32_lptim_cnt_synapse_actions to match actions_list.
Cc: Fabrice Gasnier <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/stm32-lptimer-cnt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -146,7 +146,7 @@ enum stm32_lptim_synapse_action {STM32_LPTIM_SYNAPSE_ACTION_NONE,};-staticenumcounter_synapse_actionstm32_lptim_cnt_synapse_actions[]={+staticconstenumcounter_synapse_actionstm32_lptim_cnt_synapse_actions[]={/* Index must match with stm32_lptim_cnt_polarity[] (priv->polarity) */[STM32_LPTIM_SYNAPSE_ACTION_RISING_EDGE]=COUNTER_SYNAPSE_ACTION_RISING_EDGE,[STM32_LPTIM_SYNAPSE_ACTION_FALLING_EDGE]=COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
--
2.30.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:03:25
Only a select set of modes (function, action, etc.) are valid for a
given device configuration. This patch ensures that invalid modes result
in a return -EINVAL. Such a situation should never occur in reality, but
it's good to define a default switch cases for the sake of making the
intent of the code clear.
Cc: Syed Nayyar Waris <redacted>
Cc: Kamel Bouhara <kamel.bouhara@bootlin.com>
Cc: Fabrice Gasnier <redacted>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Alexandre Torgue <redacted>
Cc: David Lechner <david@lechnology.com>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 20 +++++++----
drivers/counter/microchip-tcb-capture.c | 6 ++++
drivers/counter/stm32-lptimer-cnt.c | 10 +++---
drivers/counter/ti-eqep.c | 45 +++++++++++--------------
4 files changed, 46 insertions(+), 35 deletions(-)
@@ -273,6 +273,10 @@ static int quad8_function_set(struct counter_device *counter,*scale=2;mode_cfg|=QUAD8_CMR_QUADRATURE_X4;break;+default:+/* should never reach this path */+mutex_unlock(&priv->lock);+return-EINVAL;}}
@@ -349,7 +353,7 @@ static int quad8_action_get(struct counter_device *counter,caseQUAD8_COUNT_FUNCTION_PULSE_DIRECTION:if(synapse->signal->id==signal_a_id)*action=QUAD8_SYNAPSE_ACTION_RISING_EDGE;-break;+return0;caseQUAD8_COUNT_FUNCTION_QUADRATURE_X1:if(synapse->signal->id==signal_a_id){quad8_direction_get(counter,count,&direction);
@@ -359,17 +363,18 @@ static int quad8_action_get(struct counter_device *counter,else*action=QUAD8_SYNAPSE_ACTION_FALLING_EDGE;}-break;+return0;caseQUAD8_COUNT_FUNCTION_QUADRATURE_X2:if(synapse->signal->id==signal_a_id)*action=QUAD8_SYNAPSE_ACTION_BOTH_EDGES;-break;+return0;caseQUAD8_COUNT_FUNCTION_QUADRATURE_X4:*action=QUAD8_SYNAPSE_ACTION_BOTH_EDGES;-break;+return0;+default:+/* should never reach this path */+return-EINVAL;}--return0;}staticconststructcounter_opsquad8_ops={
@@ -529,6 +534,9 @@ static int quad8_count_mode_set(struct counter_device *counter,caseCOUNTER_COUNT_MODE_MODULO_N:cnt_mode=3;break;+default:+/* should never reach this path */+return-EINVAL;}mutex_lock(&priv->lock);
@@ -133,6 +133,9 @@ static int mchp_tc_count_function_set(struct counter_device *counter,bmr|=ATMEL_TC_QDEN|ATMEL_TC_POSEN;cmr|=ATMEL_TC_ETRGEDG_RISING|ATMEL_TC_ABETRG|ATMEL_TC_XC0;break;+default:+/* should never reach this path */+return-EINVAL;}regmap_write(priv->regmap,ATMEL_TC_BMR,bmr);
@@ -226,6 +229,9 @@ static int mchp_tc_count_action_set(struct counter_device *counter,caseMCHP_TC_SYNAPSE_ACTION_BOTH_EDGE:edge=ATMEL_TC_ETRGEDG_BOTH;break;+default:+/* should never reach this path */+return-EINVAL;}returnregmap_write_bits(priv->regmap,
@@ -206,9 +206,10 @@ static int stm32_lptim_cnt_function_set(struct counter_device *counter,priv->quadrature_mode=1;priv->polarity=STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES;return0;+default:+/* should never reach this path */+return-EINVAL;}--return-EINVAL;}staticssize_tstm32_lptim_cnt_enable_read(structcounter_device*counter,
@@ -326,9 +327,10 @@ static int stm32_lptim_cnt_action_get(struct counter_device *counter,caseSTM32_LPTIM_ENCODER_BOTH_EDGE:*action=priv->polarity;return0;+default:+/* should never reach this path */+return-EINVAL;}--return-EINVAL;}staticintstm32_lptim_cnt_action_set(structcounter_device*counter,
@@ -157,44 +157,39 @@ static int ti_eqep_action_get(struct counter_device *counter,*QEPAandQEPBtriggerQCLK.*/*action=TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;-break;+return0;caseTI_EQEP_COUNT_FUNC_DIR_COUNT:/* In direction-count mode only rising edge of QEPA is counted*andQEPBgivesdirection.*/-switch(synapse->signal->id){-caseTI_EQEP_SIGNAL_QEPA:-*action=TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;-break;-default:+if(synapse->signal->id==TI_EQEP_SIGNAL_QEPB)*action=TI_EQEP_SYNAPSE_ACTION_NONE;-break;-}-break;+else+*action=TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;+return0;caseTI_EQEP_COUNT_FUNC_UP_COUNT:caseTI_EQEP_COUNT_FUNC_DOWN_COUNT:/* In up/down-count modes only QEPA is counted and QEPB is not*used.*/-switch(synapse->signal->id){-caseTI_EQEP_SIGNAL_QEPA:-err=regmap_read(priv->regmap16,QDECCTL,&qdecctl);-if(err)-returnerr;--if(qdecctl&QDECCTL_XCR)-*action=TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;-else-*action=TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;-break;-default:+if(synapse->signal->id==TI_EQEP_SIGNAL_QEPB){*action=TI_EQEP_SYNAPSE_ACTION_NONE;-break;+return0;}-break;-}-return0;+err=regmap_read(priv->regmap16,QDECCTL,&qdecctl);+if(err)+returnerr;++if(qdecctl&QDECCTL_XCR)+*action=TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;+else+*action=TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;+return0;+default:+/* should never reach this path */+return-EINVAL;+}}staticconststructcounter_opsti_eqep_counter_ops={
--
2.30.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:03:25
The struct counter_synapse actions_list member expects a const enum
counter_synapse_action array. This patch adds the const qualifier to the
stm32_synapse_actions to match actions_list.
Cc: Fabrice Gasnier <redacted>
Cc: Benjamin Gaignard <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/stm32-timer-cnt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:03:25
Signal values will always be levels so let's be explicit it about it to
make the intent of the code clear.
Cc: Syed Nayyar Waris <redacted>
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Cc: Kamel Bouhara <kamel.bouhara@bootlin.com>
Reviewed-by: David Lechner <david@lechnology.com>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 5 +++--
drivers/counter/counter.c | 12 ++++++------
drivers/counter/interrupt-cnt.c | 4 ++--
drivers/counter/microchip-tcb-capture.c | 4 ++--
include/linux/counter.h | 12 ++++++------
5 files changed, 19 insertions(+), 18 deletions(-)
@@ -154,7 +154,7 @@ static int quad8_count_write(struct counter_device *counter,/* Only 24-bit values are supported */if(val>0xFFFFFF)-return-EINVAL;+return-ERANGE;mutex_lock(&priv->lock);
@@ -669,7 +669,7 @@ static ssize_t quad8_count_preset_write(struct counter_device *counter,/* Only 24-bit values are supported */if(preset>0xFFFFFF)-return-EINVAL;+return-ERANGE;mutex_lock(&priv->lock);
@@ -714,7 +714,7 @@ static ssize_t quad8_count_ceiling_write(struct counter_device *counter,/* Only 24-bit values are supported */if(ceiling>0xFFFFFF)-return-EINVAL;+return-ERANGE;mutex_lock(&priv->lock);
@@ -785,14 +785,14 @@ static ssize_t counter_function_store(struct device *dev,structcounter_count*constcount=component->count;constsize_tnum_functions=count->num_functions;size_tfunc_index;-enumcounter_count_functionfunction;+enumcounter_functionfunction;interr;structcounter_device*constcounter=dev_get_drvdata(dev);/* Find requested Count function mode */for(func_index=0;func_index<num_functions;func_index++){function=count->functions_list[func_index];-if(sysfs_streq(buf,counter_count_function_str[function]))+if(sysfs_streq(buf,counter_function_str[function]))break;}/* Return error if requested Count function mode not found */
@@ -880,25 +880,25 @@ static int counter_count_ext_register(}structcounter_func_avail_unit{-constenumcounter_count_function*functions_list;+constenumcounter_function*functions_list;size_tnum_functions;};-staticssize_tcounter_count_function_available_show(structdevice*dev,+staticssize_tcounter_function_available_show(structdevice*dev,structdevice_attribute*attr,char*buf){conststructcounter_device_attr*constdevattr=to_counter_attr(attr);conststructcounter_func_avail_unit*constcomponent=devattr->component;-constenumcounter_count_function*constfunc_list=component->functions_list;+constenumcounter_function*constfunc_list=component->functions_list;constsize_tnum_functions=component->num_functions;size_ti;-enumcounter_count_functionfunction;+enumcounter_functionfunction;ssize_tlen=0;for(i=0;i<num_functions;i++){function=func_list[i];len+=sprintf(buf+len,"%s\n",-counter_count_function_str[function]);+counter_function_str[function]);}returnlen;
@@ -968,7 +968,7 @@ static int counter_count_attributes_create(parm.group=group;parm.prefix="";parm.name="function_available";-parm.show=counter_count_function_available_show;+parm.show=counter_function_available_show;parm.store=NULL;parm.component=avail_comp;err=counter_attribute_create(&parm);
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:03:56
The Counter subsystem architecture and driver implementations have
changed in order to handle Counter sysfs interactions in a more
consistent way. This patch updates the Generic Counter interface
header file comments to reflect the changes.
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/counter-core.c | 3 ++
include/linux/counter.h | 72 +++++++++++++++-------------------
2 files changed, 35 insertions(+), 40 deletions(-)
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:03:57
This is in preparation for a subsequent patch implementing a character
device interface for the Counter subsystem.
Reviewed-by: David Lechner <david@lechnology.com>
Signed-off-by: William Breathitt Gray <redacted>
---
MAINTAINERS | 1 +
include/linux/counter.h | 42 +--------------------------
include/uapi/linux/counter.h | 56 ++++++++++++++++++++++++++++++++++++
3 files changed, 58 insertions(+), 41 deletions(-)
create mode 100644 include/uapi/linux/counter.h
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:03:57
The Counter subsystem architecture and driver implementations have
changed in order to handle Counter sysfs interactions in a more
consistent way. This patch updates the Generic Counter interface
documentation to reflect the changes.
Signed-off-by: William Breathitt Gray <redacted>
---
Documentation/ABI/testing/sysfs-bus-counter | 9 +-
Documentation/driver-api/generic-counter.rst | 243 ++++++++++++++-----
2 files changed, 185 insertions(+), 67 deletions(-)
@@ -277,7 +277,14 @@ What: /sys/bus/counter/devices/counterX/signalY/signal KernelVersion: 5.2 Contact: linux-iio@vger.kernel.org Description:- Signal data of Signal Y represented as a string.+ Signal level state of Signal Y. The following signal level+ states are available:++ low:+ Low level state.++ high:+ High level state. What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode KernelVersion: 5.2
@@ -250,8 +250,8 @@ for defining a counter device...kernel-doc:: drivers/counter/counter.c:export:-Implementation-==============+Driver Implementation+===================== To support a counter device, a driver must first allocate the available Counter Signals via counter_signal structures. These Signals should
@@ -267,25 +267,61 @@ 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 via-a constant counter_ops 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.+Driver callbacks must 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/miscellaneous exposure-and 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.+devm_counter_register function may be used if device memory-managed+registration is desired.++The struct counter_comp structure is used to define counter extensions+for Signals, Synapses, and Counts.++The "type" member specifies the type of high-level data (e.g. BOOL,+COUNT_DIRECTION, etc.) handled by this extension. The "``*_read``" and+"``*_write``" members can then be set by the counter device driver with+callbacks to handle that data using native C data types (i.e. u8, u64,+etc.).++Convenience macros such as ``COUNTER_COMP_COUNT_U64`` are provided for+use by driver authors. In particular, driver authors are expected to use+the provided macros for standard Counter subsystem attributes in order+to maintain a consistent interface for userspace. For example, a counter+device driver may define several standard attributes like so::++ struct counter_comp count_ext[] = {+ COUNTER_COMP_DIRECTION(count_direction_read),+ COUNTER_COMP_ENABLE(count_enable_read, count_enable_write),+ COUNTER_COMP_CEILING(count_ceiling_read, count_ceiling_write),+ };++This makes it simple to see, add, and modify the attributes that are+supported by this driver ("direction", "enable", and "ceiling") and to+maintain this code without getting lost in a web of struct braces.++Callbacks must match the function type expected for the respective+component or extension. These function types are defined in the struct+counter_comp structure as the "``*_read``" and "``*_write``" union+members.++The corresponding callback prototypes for the extensions mentioned in+the previous example above would be::++ int count_direction_read(struct counter_device *counter,+ struct counter_count *count,+ enum counter_count_direction *direction);+ int count_enable_read(struct counter_device *counter,+ struct counter_count *count, u8 *enable);+ int count_enable_write(struct counter_device *counter,+ struct counter_count *count, u8 enable);+ int count_ceiling_read(struct counter_device *counter,+ struct counter_count *count, u64 *ceiling);+ int count_ceiling_write(struct counter_device *counter,+ struct counter_count *count, u64 ceiling); Determining the type of extension to create is a matter of scope.
@@ -313,52 +349,127 @@ Determining the type of extension to create is a matter of scope. chip overheated via a device extension called "error_overtemp": /sys/bus/counter/devices/counterX/error_overtemp-Architecture-============--When the Generic Counter interface counter module is loaded, the-counter_init function is called which registers a bus_type named-"counter" to the system. Subsequently, when the module is unloaded, the-counter_exit function is called which unregisters the bus_type named-"counter" 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 a respective sysfs directory, where X is the-mentioned unique ID:-- /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.--Each Signal has a directory created to house its relevant sysfs-attributes, where Y is the unique ID of the respective Signal:-- /sys/bus/counter/devices/counterX/signalY--Similarly, each Count has a directory created to house its relevant-sysfs attributes, where Y is the unique ID of the respective Count:-- /sys/bus/counter/devices/counterX/countY--For a more detailed breakdown of the available Generic Counter interface-sysfs attributes, please refer to the-Documentation/ABI/testing/sysfs-bus-counter 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 with their-respective Signal attributes, while the count_read/count_write and-function_get/function_set driver callbacks are associated with 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.+Subsystem Architecture+======================++Counter drivers pass and take data natively (i.e. ``u8``, ``u64``, etc.)+and the shared counter module handles the translation between the sysfs+interface. This guarantees a standard userspace interface for all+counter drivers, and enables a Generic Counter chrdev interface via a+generalized device driver ABI.++A high-level view of how a count value is passed down from a counter+driver is exemplified by the following. The driver callbacks are first+registered to the Counter core component for use by the Counter+userspace interface components::++ Driver callbacks registration:+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ +----------------------------++| Counter device driver |+ +----------------------------++| Processes data from device |+ +----------------------------++ |+ -------------------+ / driver callbacks /+ -------------------+ |+ V+ +----------------------++| Counter core |+ +----------------------++| Routes device driver |+| callbacks to the |+| userspace interfaces |+ +----------------------++ |+ -------------------+ / driver callbacks /+ -------------------+ |+ +---------------++ |+ V+ +--------------------++| Counter sysfs |+ +--------------------++| Translates to the |+| standard Counter |+| sysfs output |+ +--------------------+++Thereafter, data can be transferred directly between the Counter device+driver and Counter userspace interface::++ Count data request:+ ~~~~~~~~~~~~~~~~~~~+ ----------------------+ / Counter device \+ +----------------------++| Count register: 0x28 |+ +----------------------++ |+ -----------------+ / raw count data /+ -----------------+ |+ V+ +----------------------------++| Counter device driver |+ +----------------------------++| Processes data from device |+ |----------------------------|+| Type: u64 |+| Value: 42 |+ +----------------------------++ |+ ----------+ / u64 /+ ----------+ |+ +---------------++ |+ V+ +--------------------++| Counter sysfs |+ +--------------------++| Translates to the |+| standard Counter |+| sysfs output |+ |--------------------|+| Type: const char * |+| Value: "42" |+ +--------------------++ |+ ---------------+ / const char * /+ ---------------+ |+ V+ +--------------------------------------------------++|`/sys/bus/counter/devices/counterX/countY/count` |+ +--------------------------------------------------++ \ Count: "42" /+ --------------------------------------------------++There are three primary components involved:++Counter device driver+---------------------+Communicates with the hardware device to read/write data; e.g. counter+drivers for quadrature encoders, timers, etc.++Counter core+------------+Registers the counter device driver to the system so that the respective+callbacks are called during userspace interaction.++Counter sysfs+-------------+Translates counter data to the standard Counter sysfs interface format+and vice versa.++Please refer to the ``Documentation/ABI/testing/sysfs-bus-counter`` file+for a detailed breakdown of the available Generic Counter interface+sysfs attributes.
--
2.30.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
@@ -223,19 +223,6 @@ whether an input line is differential or single-ended) and instead focus on the core idea of what the data and process represent (e.g. position as interpreted from quadrature encoding data).-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/sysfs-bus-counter 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 ==========
@@ -388,16 +375,16 @@ userspace interface components:: / driver callbacks / ------------------- |- +---------------+- |- V- +--------------------+-| Counter sysfs |- +--------------------+-| Translates to the |-| standard Counter |-| sysfs output |- +--------------------++ +---------------+---------------++| |+ V V+ +--------------------+ +---------------------++| Counter sysfs | | Counter chrdev |+ +--------------------+ +---------------------++| Translates to the | | Translates to the |+| standard Counter | | standard Counter |+| sysfs output | | character device |+ +--------------------+ +---------------------+ Thereafter, data can be transferred directly between the Counter device driver and Counter userspace interface::
@@ -453,7 +447,7 @@ driver and Counter userspace interface:: \ Count: "42" / ---------------------------------------------------There are three primary components involved:+There are four primary components involved: Counter device driver ---------------------
@@ -473,3 +467,112 @@ and vice versa. Please refer to the ``Documentation/ABI/testing/sysfs-bus-counter`` file for a detailed breakdown of the available Generic Counter interface sysfs attributes.++Counter chrdev+--------------+Translates counter data to the standard Counter character device; data+is transferred via standard character device read calls, while Counter+events are configured via ioctl calls.++Sysfs Interface+===============++Several sysfs attributes are generated by the Generic Counter interface,+and reside under the ``/sys/bus/counter/devices/counterX`` directory,+where ``X`` is to the respective counter device id. Please see+``Documentation/ABI/testing/sysfs-bus-counter`` 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.++Counter Character Device+========================++Counter character device nodes are created under the ``/dev`` directory+as ``counterX``, where ``X`` is the respective counter device id.+Defines for the standard Counter data types are exposed via the+userspace ``include/uapi/linux/counter.h`` file.++Counter events+--------------+Counter device drivers can support Counter events by utilizing the+``counter_push_event`` function::++ void counter_push_event(struct counter_device *const counter, const u8 event,+ const u8 channel);++The event id is specified by the ``event`` parameter; the event channel+id is specified by the ``channel`` parameter. When this function is+called, the Counter data associated with the respective event is+gathered, and a ``struct counter_event`` is generated for each datum and+pushed to userspace.++Counter events can be configured by users to report various Counter+data of interest. This can be conceptualized as a list of Counter+component read calls to perform. For example::++ +~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~++| COUNTER_EVENT_OVERFLOW | COUNTER_EVENT_INDEX |+ +~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~++| Channel 0 | Channel 0 |+ +------------------------+------------------------++|* Count 0 | * Signal 0 |+|* Count 1 | * Signal 0 Extension 0 |+|* Signal 3 | * Extension 4 |+| * Count 4 Extension 2 +------------------------++| * Signal 5 Extension 0 | Channel 1 |+| +------------------------++| | * Signal 4 |+| | * Signal 4 Extension 0 |+| | * Count 7 |+ +------------------------+------------------------+++When ``counter_push_event(counter, COUNTER_EVENT_INDEX, 1)`` is called+for example, it will go down the list for the ``COUNTER_EVENT_INDEX``+event channel 1 and execute the read callbacks for Signal 4, Signal 4+Extension 0, and Count 4 -- the data returned for each is pushed to a+kfifo as a ``struct counter_event``, which userspace can retrieve via a+standard read operation on the respective character device node.++Userspace+---------+Userspace applications can configure Counter events via ioctl operations+on the Counter character device node. There following ioctl codes are+supported and provided by the ``linux/counter.h`` userspace header file:++* COUNTER_ADD_WATCH_IOCTL:+ Queues a Counter watch for the specified event. The queued watches+ will not be applied until ``COUNTER_ENABLE_EVENTS_IOCTL`` is called.++* COUNTER_ENABLE_EVENTS_IOCTL:+ Enables monitoring the events specified by the Counter watches that+ were queued by ``COUNTER_ADD_WATCH_IOCTL``. If events are already+ enabled, the new set of watches replaces the old one. Calling this+ ioctl also has the effect of clearing the queue of watches added by+``COUNTER_ADD_WATCH_IOCTL``.++* COUNTER_DISABLE_EVENTS_IOCTL:+ Stops monitoring the previously enabled events.++To configure events to gather Counter data, users first populate a+``struct counter_watch`` with the relevant event id, event channel id,+and the information for the desired Counter component from which to+read, and then pass it via the ``COUNTER_ADD_WATCH_IOCTL`` ioctl+command.++Note that an event can be watched without gathering Counter data by+setting the ``component.type`` member equal to+``COUNTER_COMPONENT_NONE``. With this configuration the Counter+character device will simply populate the event timestamps for those+respective ``struct counter_event`` elements and ignore the component+value.++The ``COUNTER_ADD_WATCH_IOCTL`` command will buffer these Counter+watches. When ready, the ``COUNTER_ENABLE_EVENTS_IOCTL`` ioctl command+may be used to activate these Counter watches.++Userspace applications can then execute a ``read`` operation (optionally+calling ``poll`` first) on the Counter character device node to retrieve+``struct counter_event`` elements with the desired data.
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:03:57
This patch introduces a character device interface for the Counter
subsystem. Device data is exposed through standard character device read
operations. Device data is gathered when a Counter event is pushed by
the respective Counter device driver. Configuration is handled via ioctl
operations on the respective Counter character device node.
Cc: David Lechner <david@lechnology.com>
Cc: Gwendal Grignou <redacted>
Cc: Dan Carpenter <redacted>
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/Makefile | 2 +-
drivers/counter/counter-chrdev.c | 482 +++++++++++++++++++++++++++++++
drivers/counter/counter-chrdev.h | 14 +
drivers/counter/counter-core.c | 44 ++-
include/linux/counter.h | 45 +++
include/uapi/linux/counter.h | 77 +++++
6 files changed, 658 insertions(+), 6 deletions(-)
create mode 100644 drivers/counter/counter-chrdev.c
create mode 100644 drivers/counter/counter-chrdev.h
@@ -0,0 +1,482 @@+// SPDX-License-Identifier: GPL-2.0+/*+*GenericCountercharacterdeviceinterface+*Copyright(C)2020WilliamBreathittGray+*/++#include<linux/cdev.h>+#include<linux/counter.h>+#include<linux/err.h>+#include<linux/errno.h>+#include<linux/export.h>+#include<linux/fs.h>+#include<linux/kfifo.h>+#include<linux/list.h>+#include<linux/mutex.h>+#include<linux/nospec.h>+#include<linux/poll.h>+#include<linux/slab.h>+#include<linux/spinlock.h>+#include<linux/timekeeping.h>+#include<linux/types.h>+#include<linux/wait.h>+#include<linux/uaccess.h>++#include"counter-chrdev.h"++structcounter_comp_node{+structlist_headl;+structcounter_componentcomponent;+structcounter_compcomp;+void*parent;+};++staticssize_tcounter_chrdev_read(structfile*filp,char__user*buf,+size_tlen,loff_t*f_ps)+{+structcounter_device*constcounter=filp->private_data;+interr;+unsignedintcopied;++if(len<sizeof(structcounter_event))+return-EINVAL;++do{+if(kfifo_is_empty(&counter->events)){+if(filp->f_flags&O_NONBLOCK)+return-EAGAIN;++err=wait_event_interruptible(counter->events_wait,+!kfifo_is_empty(&counter->events));+if(err<0)+returnerr;+}++if(mutex_lock_interruptible(&counter->events_lock))+return-ERESTARTSYS;+err=kfifo_to_user(&counter->events,buf,len,&copied);+mutex_unlock(&counter->events_lock);+if(err<0)+returnerr;+}while(!copied);++returncopied;+}++static__poll_tcounter_chrdev_poll(structfile*filp,+structpoll_table_struct*pollt)+{+structcounter_device*constcounter=filp->private_data;+__poll_tevents=0;++poll_wait(filp,&counter->events_wait,pollt);++if(!kfifo_is_empty(&counter->events))+events=EPOLLIN|EPOLLRDNORM;++returnevents;+}++staticvoidcounter_events_list_free(structlist_head*constevents_list)+{+structcounter_event_node*p,*n;+structcounter_comp_node*q,*o;++list_for_each_entry_safe(p,n,events_list,l){+/* Free associated component nodes */+list_for_each_entry_safe(q,o,&p->comp_list,l){+list_del(&q->l);+kfree(q);+}++/* Free event node */+list_del(&p->l);+kfree(p);+}+}++staticintcounter_set_event_node(structcounter_device*constcounter,+structcounter_watch*constwatch,+conststructcounter_comp_node*constcfg)+{+structcounter_event_node*event_node;+structcounter_comp_node*comp_node;++/* Search for event in the list */+list_for_each_entry(event_node,&counter->next_events_list,l)+if(event_node->event==watch->event&&+event_node->channel==watch->channel)+break;++/* If event is not already in the list */+if(&event_node->l==&counter->next_events_list){+/* Allocate new event node */+event_node=kmalloc(sizeof(*event_node),GFP_ATOMIC);+if(!event_node)+return-ENOMEM;++/* Configure event node and add to the list */+event_node->event=watch->event;+event_node->channel=watch->channel;+INIT_LIST_HEAD(&event_node->comp_list);+list_add(&event_node->l,&counter->next_events_list);+}++/* Check if component watch has already been set before */+list_for_each_entry(comp_node,&event_node->comp_list,l)+if(comp_node->parent==cfg->parent&&+comp_node->comp.count_u8_read==cfg->comp.count_u8_read)+return-EINVAL;++/* Allocate component node */+comp_node=kmalloc(sizeof(*comp_node),GFP_ATOMIC);+if(!comp_node){+/* Free event node if no one else is watching */+if(list_empty(&event_node->comp_list)){+list_del(&event_node->l);+kfree(event_node);+}+return-ENOMEM;+}+*comp_node=*cfg;++/* Add component node to event node */+list_add_tail(&comp_node->l,&event_node->comp_list);++return0;+}++staticintcounter_disable_events(structcounter_device*constcounter)+{+unsignedlongflags;+interr=0;++spin_lock_irqsave(&counter->events_list_lock,flags);++counter_events_list_free(&counter->events_list);++if(counter->ops->events_configure)+err=counter->ops->events_configure(counter);++spin_unlock_irqrestore(&counter->events_list_lock,flags);++counter_events_list_free(&counter->next_events_list);++returnerr;+}++staticintcounter_add_watch(structcounter_device*constcounter,+constunsignedlongarg)+{+void__user*constuwatch=(void__user*)arg;+structcounter_watchwatch;+structcounter_comp_nodecomp_node={0};+size_tparent,id;+structcounter_comp*ext;+size_tnum_ext;+interr;++if(copy_from_user(&watch,uwatch,sizeof(watch)))+return-EFAULT;++if(watch.component.type==COUNTER_COMPONENT_NONE)+gotono_component;++parent=watch.component.parent;++/* Configure parent component info for comp node */+switch(watch.component.scope){+caseCOUNTER_SCOPE_DEVICE:+ext=counter->ext;+num_ext=counter->num_ext;+break;+caseCOUNTER_SCOPE_SIGNAL:+if(parent>=counter->num_signals)+return-EINVAL;+parent=array_index_nospec(parent,counter->num_signals);++comp_node.parent=counter->signals+parent;++ext=counter->signals[parent].ext;+num_ext=counter->signals[parent].num_ext;+break;+caseCOUNTER_SCOPE_COUNT:+if(parent>=counter->num_counts)+return-EINVAL;+parent=array_index_nospec(parent,counter->num_counts);++comp_node.parent=counter->counts+parent;++ext=counter->counts[parent].ext;+num_ext=counter->counts[parent].num_ext;+break;+default:+return-EINVAL;+}++id=watch.component.id;++/* Configure component info for comp node */+switch(watch.component.type){+caseCOUNTER_COMPONENT_SIGNAL:+if(watch.component.scope!=COUNTER_SCOPE_SIGNAL)+return-EINVAL;++comp_node.comp.type=COUNTER_COMP_SIGNAL_LEVEL;+comp_node.comp.signal_u32_read=counter->ops->signal_read;+break;+caseCOUNTER_COMPONENT_COUNT:+if(watch.component.scope!=COUNTER_SCOPE_COUNT)+return-EINVAL;++comp_node.comp.type=COUNTER_COMP_U64;+comp_node.comp.count_u64_read=counter->ops->count_read;+break;+caseCOUNTER_COMPONENT_FUNCTION:+if(watch.component.scope!=COUNTER_SCOPE_COUNT)+return-EINVAL;++comp_node.comp.type=COUNTER_COMP_FUNCTION;+comp_node.comp.count_u32_read=counter->ops->function_read;+break;+caseCOUNTER_COMPONENT_SYNAPSE_ACTION:+if(watch.component.scope!=COUNTER_SCOPE_COUNT)+return-EINVAL;+if(id>=counter->counts[parent].num_synapses)+return-EINVAL;+id=array_index_nospec(id,counter->counts[parent].num_synapses);++comp_node.comp.type=COUNTER_COMP_SYNAPSE_ACTION;+comp_node.comp.action_read=counter->ops->action_read;+comp_node.comp.priv=counter->counts[parent].synapses+id;+break;+caseCOUNTER_COMPONENT_EXTENSION:+if(id>=num_ext)+return-EINVAL;+id=array_index_nospec(id,num_ext);++comp_node.comp=ext[id];+break;+default:+return-EINVAL;+}+/* Check if any read callback is set; this is part of a union */+if(!comp_node.comp.count_u8_read)+return-EOPNOTSUPP;++no_component:+if(counter->ops->watch_validate){+err=counter->ops->watch_validate(counter,&watch);+if(err<0)+returnerr;+}++comp_node.component=watch.component;++returncounter_set_event_node(counter,&watch,&comp_node);+}++staticlongcounter_chrdev_ioctl(structfile*filp,unsignedintcmd,+unsignedlongarg)+{+structcounter_device*constcounter=filp->private_data;+unsignedlongflags;+interr=0;++switch(cmd){+caseCOUNTER_ADD_WATCH_IOCTL:+returncounter_add_watch(counter,arg);+caseCOUNTER_ENABLE_EVENTS_IOCTL:+spin_lock_irqsave(&counter->events_list_lock,flags);++counter_events_list_free(&counter->events_list);+list_replace_init(&counter->next_events_list,+&counter->events_list);++if(counter->ops->events_configure)+err=counter->ops->events_configure(counter);++spin_unlock_irqrestore(&counter->events_list_lock,flags);+returnerr;+caseCOUNTER_DISABLE_EVENTS_IOCTL:+returncounter_disable_events(counter);+default:+return-ENOIOCTLCMD;+}+}++staticintcounter_chrdev_open(structinode*inode,structfile*filp)+{+structcounter_device*constcounter=container_of(inode->i_cdev,+typeof(*counter),+chrdev);++get_device(&counter->dev);+filp->private_data=counter;++returnnonseekable_open(inode,filp);+}++staticintcounter_chrdev_release(structinode*inode,structfile*filp)+{+structcounter_device*constcounter=filp->private_data;+interr;++err=counter_disable_events(counter);+if(err<0)+returnerr;++put_device(&counter->dev);++return0;+}++staticconststructfile_operationscounter_fops={+.llseek=no_llseek,+.read=counter_chrdev_read,+.poll=counter_chrdev_poll,+.unlocked_ioctl=counter_chrdev_ioctl,+.open=counter_chrdev_open,+.release=counter_chrdev_release,+};++intcounter_chrdev_add(structcounter_device*constcounter)+{+/* Initialize Counter events lists */+INIT_LIST_HEAD(&counter->events_list);+INIT_LIST_HEAD(&counter->next_events_list);+spin_lock_init(&counter->events_list_lock);+init_waitqueue_head(&counter->events_wait);+mutex_init(&counter->events_lock);++/* Initialize character device */+cdev_init(&counter->chrdev,&counter_fops);++/* Allocate Counter events queue */+returnkfifo_alloc(&counter->events,64,GFP_ATOMIC);+}++voidcounter_chrdev_remove(structcounter_device*constcounter)+{+kfifo_free(&counter->events);+}++staticintcounter_get_data(structcounter_device*constcounter,+conststructcounter_comp_node*constcomp_node,+u64*constvalue)+{+conststructcounter_comp*constcomp=&comp_node->comp;+void*constparent=comp_node->parent;+u8value_u8=0;+u32value_u32=0;+intret;++if(comp_node->component.type==COUNTER_COMPONENT_NONE)+return0;++switch(comp->type){+caseCOUNTER_COMP_U8:+caseCOUNTER_COMP_BOOL:+switch(comp_node->component.scope){+caseCOUNTER_SCOPE_DEVICE:+ret=comp->device_u8_read(counter,&value_u8);+break;+caseCOUNTER_SCOPE_SIGNAL:+ret=comp->signal_u8_read(counter,parent,&value_u8);+break;+caseCOUNTER_SCOPE_COUNT:+ret=comp->count_u8_read(counter,parent,&value_u8);+break;+}+*value=value_u8;+returnret;+caseCOUNTER_COMP_SIGNAL_LEVEL:+caseCOUNTER_COMP_FUNCTION:+caseCOUNTER_COMP_ENUM:+caseCOUNTER_COMP_COUNT_DIRECTION:+caseCOUNTER_COMP_COUNT_MODE:+switch(comp_node->component.scope){+caseCOUNTER_SCOPE_DEVICE:+ret=comp->device_u32_read(counter,&value_u32);+break;+caseCOUNTER_SCOPE_SIGNAL:+ret=comp->signal_u32_read(counter,parent,+&value_u32);+break;+caseCOUNTER_SCOPE_COUNT:+ret=comp->count_u32_read(counter,parent,&value_u32);+break;+}+*value=value_u32;+returnret;+caseCOUNTER_COMP_U64:+switch(comp_node->component.scope){+caseCOUNTER_SCOPE_DEVICE:+returncomp->device_u64_read(counter,value);+caseCOUNTER_SCOPE_SIGNAL:+returncomp->signal_u64_read(counter,parent,value);+caseCOUNTER_SCOPE_COUNT:+returncomp->count_u64_read(counter,parent,value);+default:+return-EINVAL;+}+caseCOUNTER_COMP_SYNAPSE_ACTION:+ret=comp->action_read(counter,parent,comp->priv,+&value_u32);+*value=value_u32;+returnret;+default:+return-EINVAL;+}+}++/**+*counter_push_event-queueeventforuserspacereading+*@counter:pointertoCounterstructure+*@event:triggeredevent+*@channel:eventchannel+*+*Note:Ifnooneiswatchingfortherespectiveevent,itissilently+*discarded.+*/+voidcounter_push_event(structcounter_device*constcounter,constu8event,+constu8channel)+{+structcounter_eventev={0};+unsignedintcopied=0;+unsignedlongflags;+structcounter_event_node*event_node;+structcounter_comp_node*comp_node;++ev.timestamp=ktime_get_ns();+ev.watch.event=event;+ev.watch.channel=channel;++/* Could be in an interrupt context, so use a raw spin lock */+spin_lock_irqsave(&counter->events_list_lock,flags);++/* Search for event in the list */+list_for_each_entry(event_node,&counter->events_list,l)+if(event_node->event==event&&+event_node->channel==channel)+break;++/* If event is not in the list */+if(&event_node->l==&counter->events_list)+gotoexit_early;++/* Read and queue relevant comp for userspace */+list_for_each_entry(comp_node,&event_node->comp_list,l){+ev.watch.component=comp_node->component;+ev.status=-counter_get_data(counter,comp_node,&ev.value);++copied+=kfifo_in(&counter->events,&ev,1);+}++if(copied)+wake_up_poll(&counter->events_wait,EPOLLIN);++exit_early:+spin_unlock_irqrestore(&counter->events_list_lock,flags);+}+EXPORT_SYMBOL_GPL(counter_push_event);
@@ -3,14 +3,20 @@*GenericCounterinterface*Copyright(C)2020WilliamBreathittGray*/+#include<linux/cdev.h>#include<linux/counter.h>#include<linux/device.h>+#include<linux/device/bus.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/module.h>+#include<linux/types.h>+#include"counter-chrdev.h"#include"counter-sysfs.h"/* Provides a unique ID for each counter device */
@@ -12,6 +12,7 @@ help:@echo' acpi - ACPI tools'@echo' bpf - misc BPF tools'@echo' cgroup - cgroup tools'+@echo' counter - Counter tools'@echo' cpupower - a tool for all things x86 CPU power'@echo' debugging - tools for debugging'@echo' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
@@ -0,0 +1,53 @@+# SPDX-License-Identifier: GPL-2.0+include ../scripts/Makefile.include++bindir?=/usr/bin++ifeq ($(srctree),)+srctree:=$(patsubst%/,%,$(dir$(CURDIR)))+srctree:=$(patsubst%/,%,$(dir$(srctree)))+endif++# Do not use make's built-in rules+# (this improves performance and avoids hard-to-debug behaviour);+MAKEFLAGS+=-r++overrideCFLAGS+=-O2-Wall-g-D_GNU_SOURCE-I$(OUTPUT)include++ALL_TARGETS:=counter_example+ALL_PROGRAMS:=$(patsubst%,$(OUTPUT)%,$(ALL_TARGETS))++all:$(ALL_PROGRAMS)++exportsrctreeOUTPUTCCLDCFLAGS+include $(srctree)/tools/build/Makefile.include++#+# We need the following to be outside of kernel tree+#+$(OUTPUT)include/linux/counter.h:../../include/uapi/linux/counter.h+mkdir-p$(OUTPUT)include/linux2>&1||true+ln-sf$(CURDIR)/../../include/uapi/linux/counter.h$@++prepare:$(OUTPUT)include/linux/counter.h++COUNTER_EXAMPLE:=$(OUTPUT)counter_example.o+$(COUNTER_EXAMPLE):prepareFORCE+$(Q)$(MAKE)$(build)=counter_example+$(OUTPUT)counter_example:$(COUNTER_EXAMPLE)+$(QUIET_LINK)$(CC)$(CFLAGS)$(LDFLAGS)$<-o$@++clean:+rm-f$(ALL_PROGRAMS)+rm-rf$(OUTPUT)include/linux/counter.h+find$(if$(OUTPUT),$(OUTPUT),.)-name'*.o'-delete-o-name'\.*.d'-delete++install:$(ALL_PROGRAMS)+install-d-m755$(DESTDIR)$(bindir);\+forprogramin$(ALL_PROGRAMS);do\+install$$program$(DESTDIR)$(bindir);\+done++FORCE:++.PHONY:allinstallcleanFORCEprepare
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:04:29
The Generic Counter chrdev interface expects users to supply component
IDs in order to select Synapses for requests. In order for users to know
what component ID belongs to which Synapse this information must be
exposed. The signalZ_action_component_id attribute provides a way for
users to discover what component ID belongs to the respective Synapse.
Cc: David Lechner <david@lechnology.com>
Cc: Gwendal Grignou <redacted>
Cc: Dan Carpenter <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
Documentation/ABI/testing/sysfs-bus-counter | 7 ++++
drivers/counter/counter-sysfs.c | 45 +++++++++++++++++++++
2 files changed, 52 insertions(+)
@@ -203,6 +203,13 @@ Description: both edges: Any state transition.+What: /sys/bus/counter/devices/counterX/countY/signalZ_action_component_id+KernelVersion: 5.13+Contact: linux-iio@vger.kernel.org+Description:+ Read-only attribute that indicates the component ID of the+ respective Synapse of Count Y for Signal Z.+ What: /sys/bus/counter/devices/counterX/name KernelVersion: 5.2 Contact: linux-iio@vger.kernel.org
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:04:29
The events_queue_size sysfs attribute provides a way for users to
dynamically configure the Counter events queue size for the Counter
character device interface. The size is in number of struct
counter_event data structures. The number of elements will be rounded-up
to a power of 2 due to a requirement of the kfifo_alloc function called
during reallocation of the queue.
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: William Breathitt Gray <redacted>
---
Documentation/ABI/testing/sysfs-bus-counter | 8 ++++
drivers/counter/counter-chrdev.c | 4 ++
drivers/counter/counter-sysfs.c | 44 +++++++++++++++++++++
include/linux/counter.h | 2 +
4 files changed, 58 insertions(+)
@@ -224,6 +224,14 @@ Description: Read-only attribute that indicates the component ID of the respective extension or Synapse.+What: /sys/bus/counter/devices/counterX/events_queue_size+KernelVersion: 5.13+Contact: linux-iio@vger.kernel.org+Description:+ Size of the Counter events queue in number of struct+ counter_event data structures. The number of elements will be+ rounded-up to a power of 2.+ What: /sys/bus/counter/devices/counterX/name KernelVersion: 5.2 Contact: linux-iio@vger.kernel.org
@@ -782,12 +784,48 @@ static int counter_num_counts_read(struct counter_device *counter, u8 *val)return0;}+staticintcounter_events_queue_size_read(structcounter_device*counter,+u64*val)+{+*val=kfifo_size(&counter->events);+return0;+}++staticintcounter_events_queue_size_write(structcounter_device*counter,+u64val)+{+interr;+DECLARE_KFIFO_PTR(events,structcounter_event);++/* Verify chrdev is not currently being used */+if(!mutex_trylock(&counter->chrdev_lock))+return-EBUSY;++/* Allocate new events queue */+err=kfifo_alloc(&events,val,GFP_ATOMIC);+if(err)+returnerr;++/* Swap in new events queue */+kfifo_free(&counter->events);+counter->events.kfifo=events.kfifo;++mutex_unlock(&counter->chrdev_lock);++return0;+}+staticstructcounter_compcounter_num_signals_comp=COUNTER_COMP_DEVICE_U8("num_signals",counter_num_signals_read,NULL);staticstructcounter_compcounter_num_counts_comp=COUNTER_COMP_DEVICE_U8("num_counts",counter_num_counts_read,NULL);+staticstructcounter_compcounter_events_queue_size_comp=+COUNTER_COMP_DEVICE_U64("events_queue_size",+counter_events_queue_size_read,+counter_events_queue_size_write);+staticintcounter_sysfs_attr_add(structcounter_device*constcounter,structcounter_attribute_group*group){
@@ -826,6 +864,12 @@ static int counter_sysfs_attr_add(struct counter_device *const counter,if(err<0)returnerr;+/* Create num_counts attribute */+err=counter_attr_create(dev,group,&counter_events_queue_size_comp,+scope,NULL);+if(err<0)+returnerr;+/* Create an attribute for each extension */for(i=0;i<counter->num_ext;i++){ext=counter->ext+i;
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:04:29
The Generic Counter chrdev interface expects users to supply component
IDs in order to select extensions for requests. In order for users to
know what component ID belongs to which extension this information must
be exposed. The *_component_id attribute provides a way for users to
discover what component ID belongs to which respective extension.
Cc: David Lechner <david@lechnology.com>
Cc: Gwendal Grignou <redacted>
Cc: Dan Carpenter <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
Documentation/ABI/testing/sysfs-bus-counter | 16 ++++++++++-
drivers/counter/counter-sysfs.c | 30 ++++++++++++++++-----
2 files changed, 39 insertions(+), 7 deletions(-)
@@ -203,12 +203,26 @@ Description: both edges: Any state transition.+What: /sys/bus/counter/devices/counterX/countY/ceiling_component_id+What: /sys/bus/counter/devices/counterX/countY/floor_component_id+What: /sys/bus/counter/devices/counterX/countY/count_mode_component_id+What: /sys/bus/counter/devices/counterX/countY/direction_component_id+What: /sys/bus/counter/devices/counterX/countY/enable_component_id+What: /sys/bus/counter/devices/counterX/countY/error_noise_component_id+What: /sys/bus/counter/devices/counterX/countY/prescaler_component_id+What: /sys/bus/counter/devices/counterX/countY/preset_component_id+What: /sys/bus/counter/devices/counterX/countY/preset_enable_component_id What: /sys/bus/counter/devices/counterX/countY/signalZ_action_component_id+What: /sys/bus/counter/devices/counterX/signalY/cable_fault_component_id+What: /sys/bus/counter/devices/counterX/signalY/cable_fault_enable_component_id+What: /sys/bus/counter/devices/counterX/signalY/filter_clock_prescaler_component_id+What: /sys/bus/counter/devices/counterX/signalY/index_polarity_component_id+What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode_component_id KernelVersion: 5.13 Contact: linux-iio@vger.kernel.org Description: Read-only attribute that indicates the component ID of the- respective Synapse of Count Y for Signal Z.+ respective extension or Synapse. What: /sys/bus/counter/devices/counterX/name KernelVersion: 5.2
@@ -587,6 +587,7 @@ static int counter_signal_attrs_create(struct counter_device *const counter,interr;structcounter_compcomp;size_ti;+structcounter_comp*ext;/* Create main Signal attribute */comp=counter_signal_comp;
@@ -602,8 +603,13 @@ static int counter_signal_attrs_create(struct counter_device *const counter,/* Create an attribute for each extension */for(i=0;i<signal->num_ext;i++){-err=counter_attr_create(dev,group,signal->ext+i,scope,-signal);+ext=signal->ext+i;++err=counter_attr_create(dev,group,ext,scope,signal);+if(err<0)+returnerr;++err=counter_comp_id_attr_create(dev,group,ext->name,i);if(err<0)returnerr;}
@@ -694,6 +700,7 @@ static int counter_count_attrs_create(struct counter_device *const counter,interr;structcounter_compcomp;size_ti;+structcounter_comp*ext;/* Create main Count attribute */comp=counter_count_comp;
@@ -718,8 +725,13 @@ static int counter_count_attrs_create(struct counter_device *const counter,/* Create an attribute for each extension */for(i=0;i<count->num_ext;i++){-err=counter_attr_create(dev,group,count->ext+i,scope,-count);+ext=count->ext+i;++err=counter_attr_create(dev,group,ext,scope,count);+if(err<0)+returnerr;++err=counter_comp_id_attr_create(dev,group,ext->name,i);if(err<0)returnerr;}
@@ -815,8 +828,13 @@ static int counter_sysfs_attr_add(struct counter_device *const counter,/* Create an attribute for each extension */for(i=0;i<counter->num_ext;i++){-err=counter_attr_create(dev,group,counter->ext+i,scope,-NULL);+ext=counter->ext+i;++err=counter_attr_create(dev,group,ext,scope,NULL);+if(err<0)+returnerr;++err=counter_comp_id_attr_create(dev,group,ext->name,i);if(err<0)returnerr;}
--
2.30.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:04:29
This patch replaces the mutex I/O lock with a spinlock. This is in
preparation for a subsequent patch adding IRQ support for 104-QUAD-8
devices; we can't sleep in an interrupt context, so we'll need to use a
spinlock instead.
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 90 +++++++++++++++++++++---------------
1 file changed, 53 insertions(+), 37 deletions(-)
@@ -28,6 +29,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");/***structquad8-deviceprivatedatastructure+*@lock:locktopreventclobberingdevicestatesduringR/Wops*@counter:instanceofthecounter_device*@fck_prescaler:arrayoffilterclockprescalerconfigurations*@preset:arrayofpresetvalues
@@ -42,7 +44,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");*@base:baseportaddressofthedevice*/structquad8{-structmutexlock;+spinlock_tlock;structcounter_devicecounter;unsignedintfck_prescaler[QUAD8_NUM_COUNTERS];unsignedintpreset[QUAD8_NUM_COUNTERS];
@@ -123,6 +125,7 @@ static int quad8_count_read(struct counter_device *counter,unsignedintflags;unsignedintborrow;unsignedintcarry;+unsignedlongirqflags;inti;flags=inb(base_offset+1);
@@ -132,7 +135,7 @@ static int quad8_count_read(struct counter_device *counter,/* Borrow XOR Carry effectively doubles count range */*val=(unsignedlong)(borrow^carry)<<24;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);/* Reset Byte Pointer; transfer Counter to Output Latch */outb(QUAD8_CTR_RLD|QUAD8_RLD_RESET_BP|QUAD8_RLD_CNTR_OUT,
@@ -141,7 +144,7 @@ static int quad8_count_read(struct counter_device *counter,for(i=0;i<3;i++)*val|=(unsignedlong)inb(base_offset)<<(8*i);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -151,13 +154,14 @@ static int quad8_count_write(struct counter_device *counter,{structquad8*constpriv=counter->priv;constintbase_offset=priv->base+2*count->id;+unsignedlongirqflags;inti;/* Only 24-bit values are supported */if(val>0xFFFFFF)return-ERANGE;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);/* Reset Byte Pointer */outb(QUAD8_CTR_RLD|QUAD8_RLD_RESET_BP,base_offset+1);
@@ -182,7 +186,7 @@ static int quad8_count_write(struct counter_device *counter,/* Reset Error flag */outb(QUAD8_CTR_RLD|QUAD8_RLD_RESET_E,base_offset+1);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -200,8 +204,9 @@ static int quad8_function_read(struct counter_device *counter,{structquad8*constpriv=counter->priv;constintid=count->id;+unsignedlongirqflags;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);if(priv->quadrature_mode[id])switch(priv->quadrature_scale[id]){
@@ -218,7 +223,7 @@ static int quad8_function_read(struct counter_device *counter,else*function=COUNTER_FUNCTION_PULSE_DIRECTION;-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -233,10 +238,11 @@ static int quad8_function_write(struct counter_device *counter,unsignedint*constscale=priv->quadrature_scale+id;unsignedint*constsynchronous_mode=priv->synchronous_mode+id;constintbase_offset=priv->base+2*id+1;+unsignedlongirqflags;unsignedintmode_cfg;unsignedintidr_cfg;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);mode_cfg=priv->count_mode[id]<<1;idr_cfg=priv->index_polarity[id]<<1;
@@ -271,7 +277,7 @@ static int quad8_function_write(struct counter_device *counter,break;default:/* should never reach this path */-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return-EINVAL;}}
@@ -279,7 +285,7 @@ static int quad8_function_write(struct counter_device *counter,/* Load mode configuration to Counter Mode Register */outb(QUAD8_CTR_CMR|mode_cfg,base_offset);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -405,9 +411,10 @@ static int quad8_index_polarity_set(struct counter_device *counter,structquad8*constpriv=counter->priv;constsize_tchannel_id=signal->id-16;constintbase_offset=priv->base+2*channel_id+1;+unsignedlongirqflags;unsignedintidr_cfg=index_polarity<<1;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);idr_cfg|=priv->synchronous_mode[channel_id];
@@ -416,7 +423,7 @@ static int quad8_index_polarity_set(struct counter_device *counter,/* Load Index Control configuration to Index Control Register */outb(QUAD8_CTR_IDR|idr_cfg,base_offset);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -445,15 +452,16 @@ static int quad8_synchronous_mode_set(struct counter_device *counter,structquad8*constpriv=counter->priv;constsize_tchannel_id=signal->id-16;constintbase_offset=priv->base+2*channel_id+1;+unsignedlongirqflags;unsignedintidr_cfg=synchronous_mode;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);idr_cfg|=priv->index_polarity[channel_id]<<1;/* Index function must be non-synchronous in non-quadrature mode */if(synchronous_mode&&!priv->quadrature_mode[channel_id]){-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return-EINVAL;}
@@ -462,7 +470,7 @@ static int quad8_synchronous_mode_set(struct counter_device *counter,/* Load Index Control configuration to Index Control Register */outb(QUAD8_CTR_IDR|idr_cfg,base_offset);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -509,6 +517,7 @@ static int quad8_count_mode_write(struct counter_device *counter,unsignedintcount_mode;unsignedintmode_cfg;constintbase_offset=priv->base+2*count->id+1;+unsignedlongirqflags;/* Map Generic Counter count mode to 104-QUAD-8 count mode */switch(cnt_mode){
@@ -529,7 +538,7 @@ static int quad8_count_mode_write(struct counter_device *counter,return-EINVAL;}-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);priv->count_mode[count->id]=count_mode;
@@ -543,7 +552,7 @@ static int quad8_count_mode_write(struct counter_device *counter,/* Load mode configuration to Counter Mode Register */outb(QUAD8_CTR_CMR|mode_cfg,base_offset);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -563,9 +572,10 @@ static int quad8_count_enable_write(struct counter_device *counter,{structquad8*constpriv=counter->priv;constintbase_offset=priv->base+2*count->id;+unsignedlongirqflags;unsignedintior_cfg;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);priv->ab_enable[count->id]=enable;
@@ -574,7 +584,7 @@ static int quad8_count_enable_write(struct counter_device *counter,/* Load I/O control configuration */outb(QUAD8_CTR_IOR|ior_cfg,base_offset+1);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -625,16 +635,17 @@ static int quad8_count_preset_write(struct counter_device *counter,structcounter_count*count,u64preset){structquad8*constpriv=counter->priv;+unsignedlongirqflags;/* Only 24-bit values are supported */if(preset>0xFFFFFF)return-ERANGE;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);quad8_preset_register_set(priv,count->id,preset);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -643,8 +654,9 @@ static int quad8_count_ceiling_read(struct counter_device *counter,structcounter_count*count,u64*ceiling){structquad8*constpriv=counter->priv;+unsignedlongirqflags;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);/* Range Limit and Modulo-N count modes use preset value as ceiling */switch(priv->count_mode[count->id]){
@@ -658,7 +670,7 @@ static int quad8_count_ceiling_read(struct counter_device *counter,break;}-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -667,23 +679,24 @@ static int quad8_count_ceiling_write(struct counter_device *counter,structcounter_count*count,u64ceiling){structquad8*constpriv=counter->priv;+unsignedlongirqflags;/* Only 24-bit values are supported */if(ceiling>0xFFFFFF)return-ERANGE;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);/* Range Limit and Modulo-N count modes use preset value as ceiling */switch(priv->count_mode[count->id]){case1:case3:-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);quad8_preset_register_set(priv,count->id,ceiling);return0;}-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return-EINVAL;}
@@ -705,12 +718,13 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,{structquad8*constpriv=counter->priv;constintbase_offset=priv->base+2*count->id+1;+unsignedlongirqflags;unsignedintior_cfg;/* Preset enable is active low in Input/Output Control register */preset_enable=!preset_enable;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);priv->preset_enable[count->id]=preset_enable;
@@ -719,7 +733,7 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,/* Load I/O control configuration to Input / Output Control Register */outb(QUAD8_CTR_IOR|ior_cfg,base_offset);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -771,9 +786,10 @@ static int quad8_signal_cable_fault_enable_write(struct counter_device *counter,{structquad8*constpriv=counter->priv;constsize_tchannel_id=signal->id/2;+unsignedlongirqflags;unsignedintcable_fault_enable;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);if(enable)priv->cable_fault_enable|=BIT(channel_id);
@@ -785,7 +801,7 @@ static int quad8_signal_cable_fault_enable_write(struct counter_device *counter,outb(cable_fault_enable,priv->base+QUAD8_DIFF_ENCODER_CABLE_STATUS);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -808,8 +824,9 @@ static int quad8_signal_fck_prescaler_write(struct counter_device *counter,structquad8*constpriv=counter->priv;constsize_tchannel_id=signal->id/2;constintbase_offset=priv->base+2*channel_id;+unsignedlongirqflags;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);priv->fck_prescaler[channel_id]=prescaler;
@@ -821,7 +838,7 @@ static int quad8_signal_fck_prescaler_write(struct counter_device *counter,outb(QUAD8_CTR_RLD|QUAD8_RLD_RESET_BP|QUAD8_RLD_PRESET_PSC,base_offset+1);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -990,8 +1007,7 @@ static int quad8_probe(struct device *dev, unsigned int id)priv->counter.priv=priv;priv->base=base[id];-/* Initialize mutex */-mutex_init(&priv->lock);+spin_lock_init(&priv->lock);/* Reset all counters and disable interrupt function */outb(QUAD8_CHAN_OP_RESET_COUNTERS,base[id]+QUAD8_REG_CHAN_OP);
--
2.30.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: William Breathitt Gray <hidden> Date: 2021-03-19 11:04:30
The LSI/CSI LS7266R1 chip provides programmable output via the FLG pins.
When interrupts are enabled on the ACCES 104-QUAD-8, they occur whenever
FLG1 is active. Four functions are available for the FLG1 signal: Carry,
Compare, Carry-Borrow, and Index.
Carry:
Interrupt generated on active low Carry signal. Carry
signal toggles every time the respective channel's
counter overflows.
Compare:
Interrupt generated on active low Compare signal.
Compare signal toggles every time respective channel's
preset register is equal to the respective channel's
counter.
Carry-Borrow:
Interrupt generated on active low Carry signal and
active low Borrow signal. Carry signal toggles every
time the respective channel's counter overflows. Borrow
signal toggles every time the respective channel's
counter underflows.
Index:
Interrupt generated on active high Index signal.
These four functions correspond respectivefly to the following four
Counter event types: COUNTER_EVENT_OVERFLOW, COUNTER_EVENT_THRESHOLD,
COUNTER_EVENT_OVERFLOW_UNDERFLOW, and COUNTER_EVENT_INDEX. Interrupts
push Counter events to event channel X, where 'X' is the respective
channel whose FLG1 activated.
This patch adds IRQ support for the ACCES 104-QUAD-8. The interrupt line
numbers for the devices may be configured via the irq array module
parameter.
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 167 +++++++++++++++++++++++++++++++++--
drivers/counter/Kconfig | 6 +-
2 files changed, 164 insertions(+), 9 deletions(-)
@@ -378,13 +389,103 @@ static int quad8_action_read(struct counter_device *counter,}}+enum{+QUAD8_EVENT_NONE=-1,+QUAD8_EVENT_CARRY=0,+QUAD8_EVENT_COMPARE=1,+QUAD8_EVENT_CARRY_BORROW=2,+QUAD8_EVENT_INDEX=3,+};++staticintquad8_events_configure(structcounter_device*counter)+{+structquad8*constpriv=counter->priv;+unsignedlongirq_enabled=0;+unsignedlongirqflags;+size_tchannel;+unsignedlongior_cfg;+unsignedlongbase_offset;++spin_lock_irqsave(&priv->lock,irqflags);++/* Enable interrupts for the requested channels, disable for the rest */+for(channel=0;channel<QUAD8_NUM_COUNTERS;channel++){+if(priv->next_irq_trigger[channel]==QUAD8_EVENT_NONE)+continue;++if(priv->irq_trigger[channel]!=priv->next_irq_trigger[channel]){+/* Save new IRQ function configuration */+priv->irq_trigger[channel]=priv->next_irq_trigger[channel];++/* Load configuration to I/O Control Register */+ior_cfg=priv->ab_enable[channel]|+priv->preset_enable[channel]<<1|+priv->irq_trigger[channel]<<3;+base_offset=priv->base+2*channel+1;+outb(QUAD8_CTR_IOR|ior_cfg,base_offset);+}++/* Reset next IRQ trigger function configuration */+priv->next_irq_trigger[channel]=QUAD8_EVENT_NONE;++/* Enable IRQ line */+irq_enabled|=BIT(channel);+}++outb(irq_enabled,priv->base+QUAD8_REG_INDEX_INTERRUPT);++spin_unlock_irqrestore(&priv->lock,irqflags);++return0;+}++staticintquad8_watch_validate(structcounter_device*counter,+conststructcounter_watch*watch)+{+structquad8*constpriv=counter->priv;++if(watch->channel>QUAD8_NUM_COUNTERS-1)+return-EINVAL;++switch(watch->event){+caseCOUNTER_EVENT_OVERFLOW:+if(priv->next_irq_trigger[watch->channel]==QUAD8_EVENT_NONE)+priv->next_irq_trigger[watch->channel]=QUAD8_EVENT_CARRY;+elseif(priv->next_irq_trigger[watch->channel]!=QUAD8_EVENT_CARRY)+return-EINVAL;+return0;+caseCOUNTER_EVENT_THRESHOLD:+if(priv->next_irq_trigger[watch->channel]==QUAD8_EVENT_NONE)+priv->next_irq_trigger[watch->channel]=QUAD8_EVENT_COMPARE;+elseif(priv->next_irq_trigger[watch->channel]!=QUAD8_EVENT_COMPARE)+return-EINVAL;+return0;+caseCOUNTER_EVENT_OVERFLOW_UNDERFLOW:+if(priv->next_irq_trigger[watch->channel]==QUAD8_EVENT_NONE)+priv->next_irq_trigger[watch->channel]=QUAD8_EVENT_CARRY_BORROW;+elseif(priv->next_irq_trigger[watch->channel]!=QUAD8_EVENT_CARRY_BORROW)+return-EINVAL;+return0;+caseCOUNTER_EVENT_INDEX:+if(priv->next_irq_trigger[watch->channel]==QUAD8_EVENT_NONE)+priv->next_irq_trigger[watch->channel]=QUAD8_EVENT_INDEX;+elseif(priv->next_irq_trigger[watch->channel]!=QUAD8_EVENT_INDEX)+return-EINVAL;+return0;+default:+return-EINVAL;+}+}+staticconststructcounter_opsquad8_ops={.signal_read=quad8_signal_read,.count_read=quad8_count_read,.count_write=quad8_count_write,.function_read=quad8_function_read,.function_write=quad8_function_write,-.action_read=quad8_action_read+.action_read=quad8_action_read,+.events_configure=quad8_events_configure,+.watch_validate=quad8_watch_validate,};staticconstchar*constquad8_index_polarity_modes[]={
@@ -579,7 +680,8 @@ static int quad8_count_enable_write(struct counter_device *counter,priv->ab_enable[count->id]=enable;-ior_cfg=enable|priv->preset_enable[count->id]<<1;+ior_cfg=enable|priv->preset_enable[count->id]<<1|+priv->irq_trigger[count->id]<<3;/* Load I/O control configuration */outb(QUAD8_CTR_IOR|ior_cfg,base_offset+1);
@@ -728,7 +830,8 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,priv->preset_enable[count->id]=preset_enable;-ior_cfg=priv->ab_enable[count->id]|preset_enable<<1;+ior_cfg=priv->ab_enable[count->id]|preset_enable<<1|+priv->irq_trigger[count->id]<<3;/* Load I/O control configuration to Input / Output Control Register */outb(QUAD8_CTR_IOR|ior_cfg,base_offset);
@@ -980,11 +1083,54 @@ static struct counter_count quad8_counts[] = {QUAD8_COUNT(7,"Channel 8 Count")};+staticirqreturn_tquad8_irq_handler(intirq,void*private)+{+structquad8*constpriv=private;+constunsignedlongbase=priv->base;+unsignedlongirq_status;+unsignedlongchannel;+u8event;++irq_status=inb(base+QUAD8_REG_INTERRUPT_STATUS);+if(!irq_status)+returnIRQ_NONE;++for_each_set_bit(channel,&irq_status,QUAD8_NUM_COUNTERS){+switch(priv->irq_trigger[channel]){+caseQUAD8_EVENT_CARRY:+event=COUNTER_EVENT_OVERFLOW;+break;+caseQUAD8_EVENT_COMPARE:+event=COUNTER_EVENT_THRESHOLD;+break;+caseQUAD8_EVENT_CARRY_BORROW:+event=COUNTER_EVENT_OVERFLOW_UNDERFLOW;+break;+caseQUAD8_EVENT_INDEX:+event=COUNTER_EVENT_INDEX;+break;+default:+/* should never reach this path */+WARN_ONCE(true,"invalid interrupt trigger function %u configured for channel %lu\n",+priv->irq_trigger[channel],channel);+continue;+}++counter_push_event(&priv->counter,event,channel);+}++/* Clear pending interrupts on device */+outb(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC,base+QUAD8_REG_CHAN_OP);++returnIRQ_HANDLED;+}+staticintquad8_probe(structdevice*dev,unsignedintid){structquad8*priv;inti,j;unsignedintbase_offset;+interr;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",
@@ -1009,6 +1155,8 @@ static int quad8_probe(struct device *dev, unsigned int id)spin_lock_init(&priv->lock);+/* Reset Index/Interrupt Register */+outb(0x00,base[id]+QUAD8_REG_INDEX_INTERRUPT);/* Reset all counters and disable interrupt function */outb(QUAD8_CHAN_OP_RESET_COUNTERS,base[id]+QUAD8_REG_CHAN_OP);/* Set initial configuration for all counters */
@@ -1035,11 +1183,18 @@ static int quad8_probe(struct device *dev, unsigned int id)outb(QUAD8_CTR_IOR,base_offset+1);/* Disable index function; negative index polarity */outb(QUAD8_CTR_IDR,base_offset+1);+/* Initialize next IRQ trigger function configuration */+priv->next_irq_trigger[i]=QUAD8_EVENT_NONE;}/* Disable Differential Encoder Cable Status for all channels */outb(0xFF,base[id]+QUAD8_DIFF_ENCODER_CABLE_STATUS);-/* Enable all counters */-outb(QUAD8_CHAN_OP_ENABLE_COUNTERS,base[id]+QUAD8_REG_CHAN_OP);+/* Enable all counters and enable interrupt function */+outb(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC,base[id]+QUAD8_REG_CHAN_OP);++err=devm_request_irq(dev,irq[id],quad8_irq_handler,IRQF_SHARED,+priv->counter.name,priv);+if(err)+returnerr;returndevm_counter_register(dev,&priv->counter);}
On 3/19/21 12:00 PM, William Breathitt Gray wrote:
The struct counter_count functions_list member expects a const enum
counter_count_function array. This patch adds the const qualifier to the
stm32_lptim_cnt_functions to match functions_list.
Cc: Fabrice Gasnier <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/stm32-lptimer-cnt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Hi William,
You can add my:
Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Thanks,
Fabrice
On 3/19/21 12:00 PM, William Breathitt Gray wrote:
The struct counter_count functions_list member expects a const enum
counter_count_function array. This patch adds the const qualifier to the
stm32_count_functions to match functions_list.
Cc: Fabrice Gasnier <redacted>
Cc: Benjamin Gaignard <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/stm32-timer-cnt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Hi William,
You can add my:
Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Thanks,
Fabrice
On 3/19/21 12:00 PM, William Breathitt Gray wrote:
The struct counter_synapse actions_list member expects a const enum
counter_synapse_action array. This patch adds the const qualifier to the
stm32_lptim_cnt_synapse_actions to match actions_list.
Cc: Fabrice Gasnier <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/stm32-lptimer-cnt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Hi William,
You can add my:
Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Thanks,
Fabrice
@@ -146,7 +146,7 @@ enum stm32_lptim_synapse_action {STM32_LPTIM_SYNAPSE_ACTION_NONE,};-staticenumcounter_synapse_actionstm32_lptim_cnt_synapse_actions[]={+staticconstenumcounter_synapse_actionstm32_lptim_cnt_synapse_actions[]={/* Index must match with stm32_lptim_cnt_polarity[] (priv->polarity) */[STM32_LPTIM_SYNAPSE_ACTION_RISING_EDGE]=COUNTER_SYNAPSE_ACTION_RISING_EDGE,[STM32_LPTIM_SYNAPSE_ACTION_FALLING_EDGE]=COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
On 3/19/21 12:00 PM, William Breathitt Gray wrote:
The struct counter_synapse actions_list member expects a const enum
counter_synapse_action array. This patch adds the const qualifier to the
stm32_synapse_actions to match actions_list.
Cc: Fabrice Gasnier <redacted>
Cc: Benjamin Gaignard <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/stm32-timer-cnt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Hi William,
You can add my:
Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Thanks,
Fabrice
On 3/19/21 12:00 PM, William Breathitt Gray wrote:
Only a select set of modes (function, action, etc.) are valid for a
given device configuration. This patch ensures that invalid modes result
in a return -EINVAL. Such a situation should never occur in reality, but
it's good to define a default switch cases for the sake of making the
intent of the code clear.
Cc: Syed Nayyar Waris <redacted>
Cc: Kamel Bouhara <kamel.bouhara@bootlin.com>
Cc: Fabrice Gasnier <redacted>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Alexandre Torgue <redacted>
Cc: David Lechner <david@lechnology.com>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 20 +++++++----
drivers/counter/microchip-tcb-capture.c | 6 ++++
drivers/counter/stm32-lptimer-cnt.c | 10 +++---
Hi William,
Fro the STM32 driver, You can add my:
Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Thanks,
Fabrice
@@ -273,6 +273,10 @@ static int quad8_function_set(struct counter_device *counter,*scale=2;mode_cfg|=QUAD8_CMR_QUADRATURE_X4;break;+default:+/* should never reach this path */+mutex_unlock(&priv->lock);+return-EINVAL;}}
@@ -349,7 +353,7 @@ static int quad8_action_get(struct counter_device *counter,caseQUAD8_COUNT_FUNCTION_PULSE_DIRECTION:if(synapse->signal->id==signal_a_id)*action=QUAD8_SYNAPSE_ACTION_RISING_EDGE;-break;+return0;caseQUAD8_COUNT_FUNCTION_QUADRATURE_X1:if(synapse->signal->id==signal_a_id){quad8_direction_get(counter,count,&direction);
@@ -359,17 +363,18 @@ static int quad8_action_get(struct counter_device *counter,else*action=QUAD8_SYNAPSE_ACTION_FALLING_EDGE;}-break;+return0;caseQUAD8_COUNT_FUNCTION_QUADRATURE_X2:if(synapse->signal->id==signal_a_id)*action=QUAD8_SYNAPSE_ACTION_BOTH_EDGES;-break;+return0;caseQUAD8_COUNT_FUNCTION_QUADRATURE_X4:*action=QUAD8_SYNAPSE_ACTION_BOTH_EDGES;-break;+return0;+default:+/* should never reach this path */+return-EINVAL;}--return0;}staticconststructcounter_opsquad8_ops={
@@ -529,6 +534,9 @@ static int quad8_count_mode_set(struct counter_device *counter,caseCOUNTER_COUNT_MODE_MODULO_N:cnt_mode=3;break;+default:+/* should never reach this path */+return-EINVAL;}mutex_lock(&priv->lock);
@@ -133,6 +133,9 @@ static int mchp_tc_count_function_set(struct counter_device *counter,bmr|=ATMEL_TC_QDEN|ATMEL_TC_POSEN;cmr|=ATMEL_TC_ETRGEDG_RISING|ATMEL_TC_ABETRG|ATMEL_TC_XC0;break;+default:+/* should never reach this path */+return-EINVAL;}regmap_write(priv->regmap,ATMEL_TC_BMR,bmr);
@@ -226,6 +229,9 @@ static int mchp_tc_count_action_set(struct counter_device *counter,caseMCHP_TC_SYNAPSE_ACTION_BOTH_EDGE:edge=ATMEL_TC_ETRGEDG_BOTH;break;+default:+/* should never reach this path */+return-EINVAL;}returnregmap_write_bits(priv->regmap,
@@ -206,9 +206,10 @@ static int stm32_lptim_cnt_function_set(struct counter_device *counter,priv->quadrature_mode=1;priv->polarity=STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES;return0;+default:+/* should never reach this path */+return-EINVAL;}--return-EINVAL;}staticssize_tstm32_lptim_cnt_enable_read(structcounter_device*counter,
@@ -326,9 +327,10 @@ static int stm32_lptim_cnt_action_get(struct counter_device *counter,caseSTM32_LPTIM_ENCODER_BOTH_EDGE:*action=priv->polarity;return0;+default:+/* should never reach this path */+return-EINVAL;}--return-EINVAL;}staticintstm32_lptim_cnt_action_set(structcounter_device*counter,
@@ -157,44 +157,39 @@ static int ti_eqep_action_get(struct counter_device *counter,*QEPAandQEPBtriggerQCLK.*/*action=TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;-break;+return0;caseTI_EQEP_COUNT_FUNC_DIR_COUNT:/* In direction-count mode only rising edge of QEPA is counted*andQEPBgivesdirection.*/-switch(synapse->signal->id){-caseTI_EQEP_SIGNAL_QEPA:-*action=TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;-break;-default:+if(synapse->signal->id==TI_EQEP_SIGNAL_QEPB)*action=TI_EQEP_SYNAPSE_ACTION_NONE;-break;-}-break;+else+*action=TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;+return0;caseTI_EQEP_COUNT_FUNC_UP_COUNT:caseTI_EQEP_COUNT_FUNC_DOWN_COUNT:/* In up/down-count modes only QEPA is counted and QEPB is not*used.*/-switch(synapse->signal->id){-caseTI_EQEP_SIGNAL_QEPA:-err=regmap_read(priv->regmap16,QDECCTL,&qdecctl);-if(err)-returnerr;--if(qdecctl&QDECCTL_XCR)-*action=TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;-else-*action=TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;-break;-default:+if(synapse->signal->id==TI_EQEP_SIGNAL_QEPB){*action=TI_EQEP_SYNAPSE_ACTION_NONE;-break;+return0;}-break;-}-return0;+err=regmap_read(priv->regmap16,QDECCTL,&qdecctl);+if(err)+returnerr;++if(qdecctl&QDECCTL_XCR)+*action=TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;+else+*action=TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;+return0;+default:+/* should never reach this path */+return-EINVAL;+}}staticconststructcounter_opsti_eqep_counter_ops={
@@ -154,7 +154,7 @@ static int quad8_count_write(struct counter_device *counter,/* Only 24-bit values are supported */if(val>0xFFFFFF)-return-EINVAL;+return-ERANGE;mutex_lock(&priv->lock);
@@ -669,7 +669,7 @@ static ssize_t quad8_count_preset_write(struct counter_device *counter,/* Only 24-bit values are supported */if(preset>0xFFFFFF)-return-EINVAL;+return-ERANGE;mutex_lock(&priv->lock);
@@ -714,7 +714,7 @@ static ssize_t quad8_count_ceiling_write(struct counter_device *counter,/* Only 24-bit values are supported */if(ceiling>0xFFFFFF)-return-EINVAL;+return-ERANGE;mutex_lock(&priv->lock);
On 3/19/21 12:00 PM, William Breathitt Gray wrote:
The phrase "Counter Count function" is verbose and unintentionally
implies that function is a Count extension. This patch adjusts the
Counter subsystem code to use the more direct "Counter function" phrase
to make the intent of this code clearer.
Cc: Syed Nayyar Waris <redacted>
Cc: Patrick Havelange <patrick.havelange@essensium.com>
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Cc: Kamel Bouhara <kamel.bouhara@bootlin.com>
Cc: Fabrice Gasnier <redacted>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Alexandre Torgue <redacted>
Cc: David Lechner <david@lechnology.com>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 10 +++----
drivers/counter/counter.c | 38 ++++++++++++-------------
drivers/counter/ftm-quaddec.c | 5 ++--
drivers/counter/interrupt-cnt.c | 4 +--
drivers/counter/microchip-tcb-capture.c | 4 +--
drivers/counter/stm32-lptimer-cnt.c | 6 ++--
drivers/counter/stm32-timer-cnt.c | 10 +++----
Hi William,
For the STM32 drivers, you can add my:
Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Thanks,
Fabrice
@@ -785,14 +785,14 @@ static ssize_t counter_function_store(struct device *dev,structcounter_count*constcount=component->count;constsize_tnum_functions=count->num_functions;size_tfunc_index;-enumcounter_count_functionfunction;+enumcounter_functionfunction;interr;structcounter_device*constcounter=dev_get_drvdata(dev);/* Find requested Count function mode */for(func_index=0;func_index<num_functions;func_index++){function=count->functions_list[func_index];-if(sysfs_streq(buf,counter_count_function_str[function]))+if(sysfs_streq(buf,counter_function_str[function]))break;}/* Return error if requested Count function mode not found */
@@ -880,25 +880,25 @@ static int counter_count_ext_register(}structcounter_func_avail_unit{-constenumcounter_count_function*functions_list;+constenumcounter_function*functions_list;size_tnum_functions;};-staticssize_tcounter_count_function_available_show(structdevice*dev,+staticssize_tcounter_function_available_show(structdevice*dev,structdevice_attribute*attr,char*buf){conststructcounter_device_attr*constdevattr=to_counter_attr(attr);conststructcounter_func_avail_unit*constcomponent=devattr->component;-constenumcounter_count_function*constfunc_list=component->functions_list;+constenumcounter_function*constfunc_list=component->functions_list;constsize_tnum_functions=component->num_functions;size_ti;-enumcounter_count_functionfunction;+enumcounter_functionfunction;ssize_tlen=0;for(i=0;i<num_functions;i++){function=func_list[i];len+=sprintf(buf+len,"%s\n",-counter_count_function_str[function]);+counter_function_str[function]);}returnlen;
@@ -968,7 +968,7 @@ static int counter_count_attributes_create(parm.group=group;parm.prefix="";parm.name="function_available";-parm.show=counter_count_function_available_show;+parm.show=counter_function_available_show;parm.store=NULL;parm.component=avail_comp;err=counter_attribute_create(&parm);
On Fri, Mar 19, 2021 at 08:00:22PM +0900, William Breathitt Gray wrote:
quoted hunk
It is obvious that devm_counter_register() is used to register a Counter
device, so a comment stating such is pointless here.
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 1 -
1 file changed, 1 deletion(-)
On Fri, Mar 19, 2021 at 08:00:23PM +0900, William Breathitt Gray wrote:
quoted hunk
The 104-QUAD-8 only has two count modes where a ceiling value makes
sense: Range Limit and Modulo-N. Outside of these two modes, setting a
ceiling value is an invalid operation -- so let's report it as such by
returning -EINVAL.
Fixes: fc069262261c ("counter: 104-quad-8: Add lock guards - generic interface")
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
On Fri, Mar 19, 2021 at 08:00:24PM +0900, William Breathitt Gray wrote:
quoted hunk
When the kernel is running in secure boot mode, we lock down the kernel to
prevent userspace from modifying the running kernel image. Whilst this
includes prohibiting access to things like /dev/mem, it must also prevent
access by means of configuring driver modules in such a way as to cause a
device to access or modify the kernel image.
To this end, annotate module_param* statements that refer to hardware
configuration and indicate for future reference what type of parameter they
specify. The parameter parser in the core sees this information and can
skip such parameters with an error message if the kernel is locked down.
The module initialisation then runs as normal, but just sees whatever the
default values for those parameters is.
Note that we do still need to do the module initialisation because some
drivers have viable defaults set in case parameters aren't specified and
some drivers support automatic configuration (e.g. PNP or PCI) in addition
to manually coded parameters.
This patch annotates the 104-QUAD-8 driver.
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
On Fri, Mar 19, 2021 at 08:00:25PM +0900, William Breathitt Gray wrote:
quoted hunk
Add some safety by qualifying the quad8_preset_register_set() function
parameters as const.
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
On Fri, Mar 19, 2021 at 08:00:26PM +0900, William Breathitt Gray wrote:
quoted hunk
The struct counter_count functions_list member expects a const enum
counter_count_function array. This patch adds the const qualifier to the
quad8_count_functions_list to match functions_list.
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
On Fri, Mar 19, 2021 at 08:00:31PM +0900, William Breathitt Gray wrote:
quoted hunk
The struct counter_synapse actions_list member expects a const enum
counter_synapse_action array. This patch adds the const qualifier to the
quad8_index_actions_list and quad8_synapse_actions_list to match
actions_list.
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
On Fri, Mar 19, 2021 at 08:00:37PM +0900, William Breathitt Gray wrote:
Only a select set of modes (function, action, etc.) are valid for a
given device configuration. This patch ensures that invalid modes result
in a return -EINVAL. Such a situation should never occur in reality, but
it's good to define a default switch cases for the sake of making the
intent of the code clear.
Cc: Syed Nayyar Waris <redacted>
Cc: Kamel Bouhara <kamel.bouhara@bootlin.com>
Cc: Fabrice Gasnier <redacted>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Alexandre Torgue <redacted>
Cc: David Lechner <david@lechnology.com>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 20 +++++++----
For the 104-quad-8 driver:
Acked-by: Syed Nayyar Waris <redacted>
@@ -273,6 +273,10 @@ static int quad8_function_set(struct counter_device *counter,*scale=2;mode_cfg|=QUAD8_CMR_QUADRATURE_X4;break;+default:+/* should never reach this path */+mutex_unlock(&priv->lock);+return-EINVAL;}}
@@ -349,7 +353,7 @@ static int quad8_action_get(struct counter_device *counter,caseQUAD8_COUNT_FUNCTION_PULSE_DIRECTION:if(synapse->signal->id==signal_a_id)*action=QUAD8_SYNAPSE_ACTION_RISING_EDGE;-break;+return0;caseQUAD8_COUNT_FUNCTION_QUADRATURE_X1:if(synapse->signal->id==signal_a_id){quad8_direction_get(counter,count,&direction);
@@ -359,17 +363,18 @@ static int quad8_action_get(struct counter_device *counter,else*action=QUAD8_SYNAPSE_ACTION_FALLING_EDGE;}-break;+return0;caseQUAD8_COUNT_FUNCTION_QUADRATURE_X2:if(synapse->signal->id==signal_a_id)*action=QUAD8_SYNAPSE_ACTION_BOTH_EDGES;-break;+return0;caseQUAD8_COUNT_FUNCTION_QUADRATURE_X4:*action=QUAD8_SYNAPSE_ACTION_BOTH_EDGES;-break;+return0;+default:+/* should never reach this path */+return-EINVAL;}--return0;}staticconststructcounter_opsquad8_ops={
@@ -529,6 +534,9 @@ static int quad8_count_mode_set(struct counter_device *counter,caseCOUNTER_COUNT_MODE_MODULO_N:cnt_mode=3;break;+default:+/* should never reach this path */+return-EINVAL;}mutex_lock(&priv->lock);
@@ -133,6 +133,9 @@ static int mchp_tc_count_function_set(struct counter_device *counter,bmr|=ATMEL_TC_QDEN|ATMEL_TC_POSEN;cmr|=ATMEL_TC_ETRGEDG_RISING|ATMEL_TC_ABETRG|ATMEL_TC_XC0;break;+default:+/* should never reach this path */+return-EINVAL;}regmap_write(priv->regmap,ATMEL_TC_BMR,bmr);
@@ -226,6 +229,9 @@ static int mchp_tc_count_action_set(struct counter_device *counter,caseMCHP_TC_SYNAPSE_ACTION_BOTH_EDGE:edge=ATMEL_TC_ETRGEDG_BOTH;break;+default:+/* should never reach this path */+return-EINVAL;}returnregmap_write_bits(priv->regmap,
@@ -206,9 +206,10 @@ static int stm32_lptim_cnt_function_set(struct counter_device *counter,priv->quadrature_mode=1;priv->polarity=STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES;return0;+default:+/* should never reach this path */+return-EINVAL;}--return-EINVAL;}staticssize_tstm32_lptim_cnt_enable_read(structcounter_device*counter,
@@ -326,9 +327,10 @@ static int stm32_lptim_cnt_action_get(struct counter_device *counter,caseSTM32_LPTIM_ENCODER_BOTH_EDGE:*action=priv->polarity;return0;+default:+/* should never reach this path */+return-EINVAL;}--return-EINVAL;}staticintstm32_lptim_cnt_action_set(structcounter_device*counter,
@@ -157,44 +157,39 @@ static int ti_eqep_action_get(struct counter_device *counter,*QEPAandQEPBtriggerQCLK.*/*action=TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;-break;+return0;caseTI_EQEP_COUNT_FUNC_DIR_COUNT:/* In direction-count mode only rising edge of QEPA is counted*andQEPBgivesdirection.*/-switch(synapse->signal->id){-caseTI_EQEP_SIGNAL_QEPA:-*action=TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;-break;-default:+if(synapse->signal->id==TI_EQEP_SIGNAL_QEPB)*action=TI_EQEP_SYNAPSE_ACTION_NONE;-break;-}-break;+else+*action=TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;+return0;caseTI_EQEP_COUNT_FUNC_UP_COUNT:caseTI_EQEP_COUNT_FUNC_DOWN_COUNT:/* In up/down-count modes only QEPA is counted and QEPB is not*used.*/-switch(synapse->signal->id){-caseTI_EQEP_SIGNAL_QEPA:-err=regmap_read(priv->regmap16,QDECCTL,&qdecctl);-if(err)-returnerr;--if(qdecctl&QDECCTL_XCR)-*action=TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;-else-*action=TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;-break;-default:+if(synapse->signal->id==TI_EQEP_SIGNAL_QEPB){*action=TI_EQEP_SYNAPSE_ACTION_NONE;-break;+return0;}-break;-}-return0;+err=regmap_read(priv->regmap16,QDECCTL,&qdecctl);+if(err)+returnerr;++if(qdecctl&QDECCTL_XCR)+*action=TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;+else+*action=TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;+return0;+default:+/* should never reach this path */+return-EINVAL;+}}staticconststructcounter_opsti_eqep_counter_ops={
On Fri, Mar 19, 2021 at 08:00:38PM +0900, William Breathitt Gray wrote:
ERANGE is a semantically better error code to return when an argument
value falls outside the supported limit range of a device.
Cc: Syed Nayyar Waris <redacted>
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Cc: Fabrice Gasnier <redacted>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Alexandre Torgue <redacted>
Reviewed-by: David Lechner <david@lechnology.com>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 6 +++---
For the 104-quad-8 driver:
Acked-by: Syed Nayyar Waris <redacted>
@@ -154,7 +154,7 @@ static int quad8_count_write(struct counter_device *counter,/* Only 24-bit values are supported */if(val>0xFFFFFF)-return-EINVAL;+return-ERANGE;mutex_lock(&priv->lock);
@@ -669,7 +669,7 @@ static ssize_t quad8_count_preset_write(struct counter_device *counter,/* Only 24-bit values are supported */if(preset>0xFFFFFF)-return-EINVAL;+return-ERANGE;mutex_lock(&priv->lock);
@@ -714,7 +714,7 @@ static ssize_t quad8_count_ceiling_write(struct counter_device *counter,/* Only 24-bit values are supported */if(ceiling>0xFFFFFF)-return-EINVAL;+return-ERANGE;mutex_lock(&priv->lock);
On Fri, Mar 19, 2021 at 08:00:39PM +0900, William Breathitt Gray wrote:
Signal values will always be levels so let's be explicit it about it to
make the intent of the code clear.
Cc: Syed Nayyar Waris <redacted>
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Cc: Kamel Bouhara <kamel.bouhara@bootlin.com>
Reviewed-by: David Lechner <david@lechnology.com>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 5 +++--
For the 104-quad-8 driver:
Acked-by: Syed Nayyar Waris <redacted>
On Fri, Mar 19, 2021 at 08:00:40PM +0900, William Breathitt Gray wrote:
The phrase "Counter Count function" is verbose and unintentionally
implies that function is a Count extension. This patch adjusts the
Counter subsystem code to use the more direct "Counter function" phrase
to make the intent of this code clearer.
Cc: Syed Nayyar Waris <redacted>
Cc: Patrick Havelange <patrick.havelange@essensium.com>
Cc: Oleksij Rempel <o.rempel@pengutronix.de>
Cc: Kamel Bouhara <kamel.bouhara@bootlin.com>
Cc: Fabrice Gasnier <redacted>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Alexandre Torgue <redacted>
Cc: David Lechner <david@lechnology.com>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 10 +++----
For the 104-quad-8 driver:
Acked-by: Syed Nayyar Waris <redacted>
@@ -785,14 +785,14 @@ static ssize_t counter_function_store(struct device *dev,structcounter_count*constcount=component->count;constsize_tnum_functions=count->num_functions;size_tfunc_index;-enumcounter_count_functionfunction;+enumcounter_functionfunction;interr;structcounter_device*constcounter=dev_get_drvdata(dev);/* Find requested Count function mode */for(func_index=0;func_index<num_functions;func_index++){function=count->functions_list[func_index];-if(sysfs_streq(buf,counter_count_function_str[function]))+if(sysfs_streq(buf,counter_function_str[function]))break;}/* Return error if requested Count function mode not found */
@@ -880,25 +880,25 @@ static int counter_count_ext_register(}structcounter_func_avail_unit{-constenumcounter_count_function*functions_list;+constenumcounter_function*functions_list;size_tnum_functions;};-staticssize_tcounter_count_function_available_show(structdevice*dev,+staticssize_tcounter_function_available_show(structdevice*dev,structdevice_attribute*attr,char*buf){conststructcounter_device_attr*constdevattr=to_counter_attr(attr);conststructcounter_func_avail_unit*constcomponent=devattr->component;-constenumcounter_count_function*constfunc_list=component->functions_list;+constenumcounter_function*constfunc_list=component->functions_list;constsize_tnum_functions=component->num_functions;size_ti;-enumcounter_count_functionfunction;+enumcounter_functionfunction;ssize_tlen=0;for(i=0;i<num_functions;i++){function=func_list[i];len+=sprintf(buf+len,"%s\n",-counter_count_function_str[function]);+counter_function_str[function]);}returnlen;
@@ -968,7 +968,7 @@ static int counter_count_attributes_create(parm.group=group;parm.prefix="";parm.name="function_available";-parm.show=counter_count_function_available_show;+parm.show=counter_function_available_show;parm.store=NULL;parm.component=avail_comp;err=counter_attribute_create(&parm);
On Fri, Mar 19, 2021 at 08:00:51PM +0900, William Breathitt Gray wrote:
This patch replaces the mutex I/O lock with a spinlock. This is in
preparation for a subsequent patch adding IRQ support for 104-QUAD-8
devices; we can't sleep in an interrupt context, so we'll need to use a
spinlock instead.
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 90 +++++++++++++++++++++---------------
1 file changed, 53 insertions(+), 37 deletions(-)
@@ -28,6 +29,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");/***structquad8-deviceprivatedatastructure+*@lock:locktopreventclobberingdevicestatesduringR/Wops*@counter:instanceofthecounter_device*@fck_prescaler:arrayoffilterclockprescalerconfigurations*@preset:arrayofpresetvalues
@@ -42,7 +44,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");*@base:baseportaddressofthedevice*/structquad8{-structmutexlock;+spinlock_tlock;structcounter_devicecounter;unsignedintfck_prescaler[QUAD8_NUM_COUNTERS];unsignedintpreset[QUAD8_NUM_COUNTERS];
@@ -123,6 +125,7 @@ static int quad8_count_read(struct counter_device *counter,unsignedintflags;unsignedintborrow;unsignedintcarry;+unsignedlongirqflags;inti;flags=inb(base_offset+1);
@@ -132,7 +135,7 @@ static int quad8_count_read(struct counter_device *counter,/* Borrow XOR Carry effectively doubles count range */*val=(unsignedlong)(borrow^carry)<<24;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);/* Reset Byte Pointer; transfer Counter to Output Latch */outb(QUAD8_CTR_RLD|QUAD8_RLD_RESET_BP|QUAD8_RLD_CNTR_OUT,
@@ -141,7 +144,7 @@ static int quad8_count_read(struct counter_device *counter,for(i=0;i<3;i++)*val|=(unsignedlong)inb(base_offset)<<(8*i);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -151,13 +154,14 @@ static int quad8_count_write(struct counter_device *counter,{structquad8*constpriv=counter->priv;constintbase_offset=priv->base+2*count->id;+unsignedlongirqflags;inti;/* Only 24-bit values are supported */if(val>0xFFFFFF)return-ERANGE;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);/* Reset Byte Pointer */outb(QUAD8_CTR_RLD|QUAD8_RLD_RESET_BP,base_offset+1);
@@ -182,7 +186,7 @@ static int quad8_count_write(struct counter_device *counter,/* Reset Error flag */outb(QUAD8_CTR_RLD|QUAD8_RLD_RESET_E,base_offset+1);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -200,8 +204,9 @@ static int quad8_function_read(struct counter_device *counter,{structquad8*constpriv=counter->priv;constintid=count->id;+unsignedlongirqflags;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);if(priv->quadrature_mode[id])switch(priv->quadrature_scale[id]){
@@ -218,7 +223,7 @@ static int quad8_function_read(struct counter_device *counter,else*function=COUNTER_FUNCTION_PULSE_DIRECTION;-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -233,10 +238,11 @@ static int quad8_function_write(struct counter_device *counter,unsignedint*constscale=priv->quadrature_scale+id;unsignedint*constsynchronous_mode=priv->synchronous_mode+id;constintbase_offset=priv->base+2*id+1;+unsignedlongirqflags;unsignedintmode_cfg;unsignedintidr_cfg;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);mode_cfg=priv->count_mode[id]<<1;idr_cfg=priv->index_polarity[id]<<1;
@@ -271,7 +277,7 @@ static int quad8_function_write(struct counter_device *counter,break;default:/* should never reach this path */-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return-EINVAL;}}
@@ -279,7 +285,7 @@ static int quad8_function_write(struct counter_device *counter,/* Load mode configuration to Counter Mode Register */outb(QUAD8_CTR_CMR|mode_cfg,base_offset);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -405,9 +411,10 @@ static int quad8_index_polarity_set(struct counter_device *counter,structquad8*constpriv=counter->priv;constsize_tchannel_id=signal->id-16;constintbase_offset=priv->base+2*channel_id+1;+unsignedlongirqflags;unsignedintidr_cfg=index_polarity<<1;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);idr_cfg|=priv->synchronous_mode[channel_id];
@@ -416,7 +423,7 @@ static int quad8_index_polarity_set(struct counter_device *counter,/* Load Index Control configuration to Index Control Register */outb(QUAD8_CTR_IDR|idr_cfg,base_offset);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -445,15 +452,16 @@ static int quad8_synchronous_mode_set(struct counter_device *counter,structquad8*constpriv=counter->priv;constsize_tchannel_id=signal->id-16;constintbase_offset=priv->base+2*channel_id+1;+unsignedlongirqflags;unsignedintidr_cfg=synchronous_mode;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);idr_cfg|=priv->index_polarity[channel_id]<<1;/* Index function must be non-synchronous in non-quadrature mode */if(synchronous_mode&&!priv->quadrature_mode[channel_id]){-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return-EINVAL;}
@@ -462,7 +470,7 @@ static int quad8_synchronous_mode_set(struct counter_device *counter,/* Load Index Control configuration to Index Control Register */outb(QUAD8_CTR_IDR|idr_cfg,base_offset);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -509,6 +517,7 @@ static int quad8_count_mode_write(struct counter_device *counter,unsignedintcount_mode;unsignedintmode_cfg;constintbase_offset=priv->base+2*count->id+1;+unsignedlongirqflags;/* Map Generic Counter count mode to 104-QUAD-8 count mode */switch(cnt_mode){
@@ -529,7 +538,7 @@ static int quad8_count_mode_write(struct counter_device *counter,return-EINVAL;}-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);priv->count_mode[count->id]=count_mode;
@@ -543,7 +552,7 @@ static int quad8_count_mode_write(struct counter_device *counter,/* Load mode configuration to Counter Mode Register */outb(QUAD8_CTR_CMR|mode_cfg,base_offset);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -563,9 +572,10 @@ static int quad8_count_enable_write(struct counter_device *counter,{structquad8*constpriv=counter->priv;constintbase_offset=priv->base+2*count->id;+unsignedlongirqflags;unsignedintior_cfg;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);priv->ab_enable[count->id]=enable;
@@ -574,7 +584,7 @@ static int quad8_count_enable_write(struct counter_device *counter,/* Load I/O control configuration */outb(QUAD8_CTR_IOR|ior_cfg,base_offset+1);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -625,16 +635,17 @@ static int quad8_count_preset_write(struct counter_device *counter,structcounter_count*count,u64preset){structquad8*constpriv=counter->priv;+unsignedlongirqflags;/* Only 24-bit values are supported */if(preset>0xFFFFFF)return-ERANGE;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);quad8_preset_register_set(priv,count->id,preset);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -643,8 +654,9 @@ static int quad8_count_ceiling_read(struct counter_device *counter,structcounter_count*count,u64*ceiling){structquad8*constpriv=counter->priv;+unsignedlongirqflags;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);/* Range Limit and Modulo-N count modes use preset value as ceiling */switch(priv->count_mode[count->id]){
@@ -658,7 +670,7 @@ static int quad8_count_ceiling_read(struct counter_device *counter,break;}-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -667,23 +679,24 @@ static int quad8_count_ceiling_write(struct counter_device *counter,structcounter_count*count,u64ceiling){structquad8*constpriv=counter->priv;+unsignedlongirqflags;/* Only 24-bit values are supported */if(ceiling>0xFFFFFF)return-ERANGE;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);/* Range Limit and Modulo-N count modes use preset value as ceiling */switch(priv->count_mode[count->id]){case1:case3:-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);quad8_preset_register_set(priv,count->id,ceiling);return0;}-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return-EINVAL;}
@@ -705,12 +718,13 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,{structquad8*constpriv=counter->priv;constintbase_offset=priv->base+2*count->id+1;+unsignedlongirqflags;unsignedintior_cfg;/* Preset enable is active low in Input/Output Control register */preset_enable=!preset_enable;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);priv->preset_enable[count->id]=preset_enable;
@@ -719,7 +733,7 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,/* Load I/O control configuration to Input / Output Control Register */outb(QUAD8_CTR_IOR|ior_cfg,base_offset);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -771,9 +786,10 @@ static int quad8_signal_cable_fault_enable_write(struct counter_device *counter,{structquad8*constpriv=counter->priv;constsize_tchannel_id=signal->id/2;+unsignedlongirqflags;unsignedintcable_fault_enable;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);if(enable)priv->cable_fault_enable|=BIT(channel_id);
@@ -785,7 +801,7 @@ static int quad8_signal_cable_fault_enable_write(struct counter_device *counter,outb(cable_fault_enable,priv->base+QUAD8_DIFF_ENCODER_CABLE_STATUS);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -808,8 +824,9 @@ static int quad8_signal_fck_prescaler_write(struct counter_device *counter,structquad8*constpriv=counter->priv;constsize_tchannel_id=signal->id/2;constintbase_offset=priv->base+2*channel_id;+unsignedlongirqflags;-mutex_lock(&priv->lock);+spin_lock_irqsave(&priv->lock,irqflags);priv->fck_prescaler[channel_id]=prescaler;
@@ -821,7 +838,7 @@ static int quad8_signal_fck_prescaler_write(struct counter_device *counter,outb(QUAD8_CTR_RLD|QUAD8_RLD_RESET_BP|QUAD8_RLD_PRESET_PSC,base_offset+1);-mutex_unlock(&priv->lock);+spin_unlock_irqrestore(&priv->lock,irqflags);return0;}
@@ -990,8 +1007,7 @@ static int quad8_probe(struct device *dev, unsigned int id)priv->counter.priv=priv;priv->base=base[id];-/* Initialize mutex */-mutex_init(&priv->lock);+spin_lock_init(&priv->lock);/* Reset all counters and disable interrupt function */outb(QUAD8_CHAN_OP_RESET_COUNTERS,base[id]+QUAD8_REG_CHAN_OP);
On Fri, Mar 19, 2021 at 08:00:52PM +0900, William Breathitt Gray wrote:
The LSI/CSI LS7266R1 chip provides programmable output via the FLG pins.
When interrupts are enabled on the ACCES 104-QUAD-8, they occur whenever
FLG1 is active. Four functions are available for the FLG1 signal: Carry,
Compare, Carry-Borrow, and Index.
Carry:
Interrupt generated on active low Carry signal. Carry
signal toggles every time the respective channel's
counter overflows.
Compare:
Interrupt generated on active low Compare signal.
Compare signal toggles every time respective channel's
preset register is equal to the respective channel's
counter.
Carry-Borrow:
Interrupt generated on active low Carry signal and
active low Borrow signal. Carry signal toggles every
time the respective channel's counter overflows. Borrow
signal toggles every time the respective channel's
counter underflows.
Index:
Interrupt generated on active high Index signal.
These four functions correspond respectivefly to the following four
Counter event types: COUNTER_EVENT_OVERFLOW, COUNTER_EVENT_THRESHOLD,
COUNTER_EVENT_OVERFLOW_UNDERFLOW, and COUNTER_EVENT_INDEX. Interrupts
push Counter events to event channel X, where 'X' is the respective
channel whose FLG1 activated.
This patch adds IRQ support for the ACCES 104-QUAD-8. The interrupt line
numbers for the devices may be configured via the irq array module
parameter.
Cc: Syed Nayyar Waris <redacted>
Signed-off-by: William Breathitt Gray <redacted>
---
drivers/counter/104-quad-8.c | 167 +++++++++++++++++++++++++++++++++--
drivers/counter/Kconfig | 6 +-
2 files changed, 164 insertions(+), 9 deletions(-)
@@ -378,13 +389,103 @@ static int quad8_action_read(struct counter_device *counter,}}+enum{+QUAD8_EVENT_NONE=-1,+QUAD8_EVENT_CARRY=0,+QUAD8_EVENT_COMPARE=1,+QUAD8_EVENT_CARRY_BORROW=2,+QUAD8_EVENT_INDEX=3,+};++staticintquad8_events_configure(structcounter_device*counter)+{+structquad8*constpriv=counter->priv;+unsignedlongirq_enabled=0;+unsignedlongirqflags;+size_tchannel;+unsignedlongior_cfg;+unsignedlongbase_offset;++spin_lock_irqsave(&priv->lock,irqflags);++/* Enable interrupts for the requested channels, disable for the rest */+for(channel=0;channel<QUAD8_NUM_COUNTERS;channel++){+if(priv->next_irq_trigger[channel]==QUAD8_EVENT_NONE)+continue;++if(priv->irq_trigger[channel]!=priv->next_irq_trigger[channel]){+/* Save new IRQ function configuration */+priv->irq_trigger[channel]=priv->next_irq_trigger[channel];++/* Load configuration to I/O Control Register */+ior_cfg=priv->ab_enable[channel]|+priv->preset_enable[channel]<<1|+priv->irq_trigger[channel]<<3;+base_offset=priv->base+2*channel+1;+outb(QUAD8_CTR_IOR|ior_cfg,base_offset);+}++/* Reset next IRQ trigger function configuration */+priv->next_irq_trigger[channel]=QUAD8_EVENT_NONE;++/* Enable IRQ line */+irq_enabled|=BIT(channel);+}++outb(irq_enabled,priv->base+QUAD8_REG_INDEX_INTERRUPT);++spin_unlock_irqrestore(&priv->lock,irqflags);++return0;+}++staticintquad8_watch_validate(structcounter_device*counter,+conststructcounter_watch*watch)+{+structquad8*constpriv=counter->priv;++if(watch->channel>QUAD8_NUM_COUNTERS-1)+return-EINVAL;++switch(watch->event){+caseCOUNTER_EVENT_OVERFLOW:+if(priv->next_irq_trigger[watch->channel]==QUAD8_EVENT_NONE)+priv->next_irq_trigger[watch->channel]=QUAD8_EVENT_CARRY;+elseif(priv->next_irq_trigger[watch->channel]!=QUAD8_EVENT_CARRY)+return-EINVAL;+return0;+caseCOUNTER_EVENT_THRESHOLD:+if(priv->next_irq_trigger[watch->channel]==QUAD8_EVENT_NONE)+priv->next_irq_trigger[watch->channel]=QUAD8_EVENT_COMPARE;+elseif(priv->next_irq_trigger[watch->channel]!=QUAD8_EVENT_COMPARE)+return-EINVAL;+return0;+caseCOUNTER_EVENT_OVERFLOW_UNDERFLOW:+if(priv->next_irq_trigger[watch->channel]==QUAD8_EVENT_NONE)+priv->next_irq_trigger[watch->channel]=QUAD8_EVENT_CARRY_BORROW;+elseif(priv->next_irq_trigger[watch->channel]!=QUAD8_EVENT_CARRY_BORROW)+return-EINVAL;+return0;+caseCOUNTER_EVENT_INDEX:+if(priv->next_irq_trigger[watch->channel]==QUAD8_EVENT_NONE)+priv->next_irq_trigger[watch->channel]=QUAD8_EVENT_INDEX;+elseif(priv->next_irq_trigger[watch->channel]!=QUAD8_EVENT_INDEX)+return-EINVAL;+return0;+default:+return-EINVAL;+}+}+staticconststructcounter_opsquad8_ops={.signal_read=quad8_signal_read,.count_read=quad8_count_read,.count_write=quad8_count_write,.function_read=quad8_function_read,.function_write=quad8_function_write,-.action_read=quad8_action_read+.action_read=quad8_action_read,+.events_configure=quad8_events_configure,+.watch_validate=quad8_watch_validate,};staticconstchar*constquad8_index_polarity_modes[]={
@@ -579,7 +680,8 @@ static int quad8_count_enable_write(struct counter_device *counter,priv->ab_enable[count->id]=enable;-ior_cfg=enable|priv->preset_enable[count->id]<<1;+ior_cfg=enable|priv->preset_enable[count->id]<<1|+priv->irq_trigger[count->id]<<3;/* Load I/O control configuration */outb(QUAD8_CTR_IOR|ior_cfg,base_offset+1);
@@ -728,7 +830,8 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,priv->preset_enable[count->id]=preset_enable;-ior_cfg=priv->ab_enable[count->id]|preset_enable<<1;+ior_cfg=priv->ab_enable[count->id]|preset_enable<<1|+priv->irq_trigger[count->id]<<3;/* Load I/O control configuration to Input / Output Control Register */outb(QUAD8_CTR_IOR|ior_cfg,base_offset);
@@ -980,11 +1083,54 @@ static struct counter_count quad8_counts[] = {QUAD8_COUNT(7,"Channel 8 Count")};+staticirqreturn_tquad8_irq_handler(intirq,void*private)+{+structquad8*constpriv=private;+constunsignedlongbase=priv->base;+unsignedlongirq_status;+unsignedlongchannel;+u8event;++irq_status=inb(base+QUAD8_REG_INTERRUPT_STATUS);+if(!irq_status)+returnIRQ_NONE;++for_each_set_bit(channel,&irq_status,QUAD8_NUM_COUNTERS){+switch(priv->irq_trigger[channel]){+caseQUAD8_EVENT_CARRY:+event=COUNTER_EVENT_OVERFLOW;+break;+caseQUAD8_EVENT_COMPARE:+event=COUNTER_EVENT_THRESHOLD;+break;+caseQUAD8_EVENT_CARRY_BORROW:+event=COUNTER_EVENT_OVERFLOW_UNDERFLOW;+break;+caseQUAD8_EVENT_INDEX:+event=COUNTER_EVENT_INDEX;+break;+default:+/* should never reach this path */+WARN_ONCE(true,"invalid interrupt trigger function %u configured for channel %lu\n",+priv->irq_trigger[channel],channel);+continue;+}++counter_push_event(&priv->counter,event,channel);+}++/* Clear pending interrupts on device */+outb(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC,base+QUAD8_REG_CHAN_OP);++returnIRQ_HANDLED;+}+staticintquad8_probe(structdevice*dev,unsignedintid){structquad8*priv;inti,j;unsignedintbase_offset;+interr;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",
@@ -1009,6 +1155,8 @@ static int quad8_probe(struct device *dev, unsigned int id)spin_lock_init(&priv->lock);+/* Reset Index/Interrupt Register */+outb(0x00,base[id]+QUAD8_REG_INDEX_INTERRUPT);/* Reset all counters and disable interrupt function */outb(QUAD8_CHAN_OP_RESET_COUNTERS,base[id]+QUAD8_REG_CHAN_OP);/* Set initial configuration for all counters */
@@ -1035,11 +1183,18 @@ static int quad8_probe(struct device *dev, unsigned int id)outb(QUAD8_CTR_IOR,base_offset+1);/* Disable index function; negative index polarity */outb(QUAD8_CTR_IDR,base_offset+1);+/* Initialize next IRQ trigger function configuration */+priv->next_irq_trigger[i]=QUAD8_EVENT_NONE;}/* Disable Differential Encoder Cable Status for all channels */outb(0xFF,base[id]+QUAD8_DIFF_ENCODER_CABLE_STATUS);-/* Enable all counters */-outb(QUAD8_CHAN_OP_ENABLE_COUNTERS,base[id]+QUAD8_REG_CHAN_OP);+/* Enable all counters and enable interrupt function */+outb(QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC,base[id]+QUAD8_REG_CHAN_OP);++err=devm_request_irq(dev,irq[id],quad8_irq_handler,IRQF_SHARED,+priv->counter.name,priv);+if(err)+returnerr;returndevm_counter_register(dev,&priv->counter);}