Add RZ/G2L MTU3a Core, Counter and pwm driver
Subsystems (7)
Biju Das
maintainerv15 cover Add RZ/G2L MTU3a Core, Counter and pwm driver
The RZ/G2L multi-function timer pulse unit 3 (MTU3a) is embedded in the Renesas RZ/G2L family SoC's. It consists of eight 16-bit timer channels and one 32-bit timer channel. It supports the following functions
- Counter
- Timer
- PWM
This patch series aims to add core, counter and pwm driver for MTU3a. The core instantiates child devices using mfd api.
The 8/16/32 bit registers are mixed in each channel. The HW specifications of the IP is described in patch#1.
Current patch set is tested for PWM mode1 on MTU3 channel and 16 and 32 bit phase counting modes on MTU1 and MTU2 channels.
clock event/source driver will be added later.
Ref:
[1] https://patchwork.kernel.org/project/linux-renesas-soc/patch/[email protected]/
[2] https://patchwork.kernel.org/project/linux-renesas-soc/patch/[email protected]/
v14->v15:
* Updated copyright header and Limitations section
* Moved register definitions to <linux/mfd/rz-mtu3.h>
* Introduced new mapping table struct rz_mtu3_channel_io_map to hold the index of the lowest PWM and the number of PWMs handled by the HW channel.
* Introduced struct rz_mtu3_pwm_channel to hold mtu3 channel data and mapping table.
* Replaced rz_mtu3_get_hw_channel->rz_mtu3_get_channel and channel->hwpwm. The rz_mtu3_get_channel() returns struct rz_mtu3_pwm_channel*
* Dropped rz_mtu3_pwm_is_second_channel() as same can be obtained directly with new mapping (ie, priv->map->channel == pwm->hwpwm)
* Replaced ch_index->ch throughout and used "priv - rz_mtu3_pwm->channel_data" to find ch and dropped rz_mtu3_get_hw_channel_index().
* Optimized rz_mtu3_pwm_is_ch_enabled() by exit early, if is_channel_en is false.
* Updated rz_mtu3_pwm_request() and added comments.
* Introduced a bug in the driver by introducing enable_count, which increment/ decrement during enable()/disable().
* Reduced variable scope in rz_mtu3_pwm_get_state() by moving most of variables inside the if statement.
* Updated probe() to assign the struct rz_mtu3_pwm_channel values.v13->v14:
* Added helper macros for initializing 8/16/32 channel reg offset table in "drivers/mfd/rz-mtu3.h"
* Replaced "off"->offset in read_write()
* Replaced __LINUX_RZ_MTU3_H__->__MFD_RZ_MTU3_H__
* Added header file device.h and mutex.h
* Updated rz_mtu3_request_channel()
* Replaced channel_index->channel_number in struct rz_mtu3_channel
* Dropped redundant comments.
* Renamed channel number macros from RZ_MTU*->RZ_MTU3_CHAN_*
* Added core driver specific private data in struct rz_mtu3 and updated the comments. This replaces mmio from struct rz_mtu3.
* Started using actual offset in channel reg table and removed ch_reg_offsets table Also simplified the code 8/16/32 bits read_write() and removed base from struct rz_mtu3_channel.
* Simplified rz_mtu3_start_stop_ch()/rz_mtu3_is_enabled() by adding helper functions rz_mtu3_get_tstr_offset()/rz_mtu3_get_tstr_bit_pos().
* Added Acked-by tag from William Breathitt Gray
* Replaced RZ_MTU1->RZ_MTU3_CHAN_1 and retained the Rb/ack tag as
it is trivial change.
* Updated commit description
* Updated Limitations section.
* Replaced the macros RZ_MTU*->RZ_MTU3_CHAN_* in probe()
* Fixed a kernel crash in error path by moving rz_mtu3_pwm->chip.dev before devm_add_action_or_reset()
* Added pm_runtime_idle() and simplified error paths for devm_add_action_or_reset() and devm_pwmchip_add().
v12->v13:
* Updated kernel version in bindings from 6.3->6.4 as it is too late.
* Moved RZ_MTU3_TMDR1_* macros from pwm driver to rz-mtu3.h.
* Updated commit description for the pwm driver
* Moved RZ_MTU3_TMDR1_MD_* macros to rz_mtu3.h
* Updated Limitations section on PWM driver.
* Removed PWM mode1 references from the driver.
* Dropped prescale and duty_cycle from struct rz_mtu3_pwm_chip.
* Replaced rz_mtu3_pwm_mode1_num_ios->rz_mtu3_hw_channel_ios.
* Avoided race condition in rz_mtu3_pwm_request()/rz_mtu3_pwm_free().
* Updated get_state() by adding dc > pv check and added a comment about overflow condition.
* Moved overflow condition check from config->probe()
* Replaced pm_runtime_resume_and_get with unconditional pm_runtime_get_sync() in config()
* Added error check for clk_prepare_enable() in probe() and propagating error to the caller for pm_runtime_resume()
* clk_get_rate() is called after enabling the clock and clk_rate_exclusive_put()v11->v12:
* As per [1] & [2] Kept bindings in timer subsytems
* Moved core driver from timer to MFD as child devices are instantiated using MFD API's.
* Moved header fine from clocksource/rz-mtu3.h->linux/mfd/rz-mtu3.h
* Removed Select MFD_CORE option from config.v10->v11:
* Added Rb tag from William Breathitt Gray for the driver patch
* Replaced count2 channel name from "combined"->"cascaded", as channels are cascaded
* Simplified the locking by adding the helper functions rz_mtu3_lock_if_counter_is_valid, rz_mtu3_lock_if_count_is_enabled, and rz_mtu3_lock_if_ch0_is_enabled.
* Added the MAINTAINERS entries for the driver.v9->v10:
* Added logs from PWM and counter
* Added Rb tag from William Breathitt Gray for sysfs counter doc
* Added helper function for rz_mtu3_count_{action,function}_read
* Added priv->lock in rz_mtu3_count_function_read and rz_mtu3_count_ direction_read.
* Added ch->is_busy check for rz_mtu3_action_read()
* Added rz_mtu3_is_ch0_enabled() for device specific sysfs variables.
* Added ch->is_busy check for device specific sysfs variables.v8->v9:
* Added prescale/duty_cycle variables to struct rz_mtu3_pwm_chip and cached this values in rz_mtu3_pwm_config and used this cached values in get_state(), if PWM is disabled.
* Added return code for get_state().
* Added available blocks for external_input_phase_clock_select_available
* Removed the "This attribute" from the external_input_phase_clock_select description, and capitalize the word "counter" from description.
* Removed the "This attribute" from the cascade_counts_enable description, and capitalize "counts" and "counter"
* Moved these device-level configuration blocks to top of the file.
* Added count_is_enabled variable to struct rz_mtu3_cnt
* Added check for ch->is_busy and count_is_enabled before every Counter callback to ensure we do not try to access a busy channel used by other subsystem(eg: pwm).
* Removed id parameter from rz_mtu3_32bit_cnt_setting()
* Made definition of rz_mtu3_get_ch() in single line.
* Replaced break->return in rz_mtu3_32bit_cnt_setting(), rz_mtu3_count_function_read() and rz_mtu3_initialize_counter() and removed redundant return 0.
* Simplified synapse signal check for rz_mtu3_action_read().v7->v8:
* Add locking for RMW on rz_mtu3_shared_reg_update_bit()
* Replaced enum rz_mtu3_functions with channel busy flag
* Added API for request and release a channel.
* Replaced cascade_enable->cascade_counts_enable
* Updated commit header and description
* Added external_input_phase_clock_select_available entry for driver- specific enum attribute and created a new entry block for it.
* Add a line stating cascade_counts_enable is a boolean attribute.
* Added missing 'component_id' suffix.
* Simplified rz_mtu3_initialize_counter by calling rz_mtu3_request_ channel() and release the acquired sibling channel in case of error.
* Simplified rz_mtu3_terminate_counter by calling rz_mtu3_release_ channel().
* Removed unused ceiling and ch_id from rz_mtu3_count_write()
* Replaced the error -EINVAL->-EBUSY for rz_mtu3_is_counter_invalid()
* Avoided race between rz_mtu3_count_{read, write} with rz_mtu3_ cascade_counts_enable_set() by adding locks and moved the lock before rz_mtu3_is_counter_invalid()
* Protected the rz_mtu3_count_ceiling_read() function with a lock to make sure the cascade operation mode doesn't not change and that the priv data structure accesses don't race when they are changed in the ceiling_write() callback.
* Added lock in rz_mtu3_cascade_enable_set() to make sure the other callbacks don't try to read the LWA state while updating LWA.
* Added lock in rz_mtu3_ext_input_phase_clock_select_set() to ensure the other callbacks don't try to read the PHCKSEL state while updating PHCKSEL.
* Added lock to avoid race between rz_mtu3_count_function_write() and rz_mtu3_action_read()
* Updated rz_mtu3_action_read to return 0, if Synapse is in COUNTER_SYNAPSE _ACTION_NONE state.
* Replaced sysfs variable cascade_enable->cascade_counts_enable
* Renamed rz_mtu3_cascade_enable_get->rz_mtu3_cascade_counts_enable_get
* Renamed rz_mtu3_cascade_enable_set->rz_mtu3_cascade_counts_enable_set
* Removed redundent ceiling assignment from rz_mtu3_count_ceiling_read()
* Removed unused ceiling and ch_id from rz_mtu3_count_write().
* Simplified rz_mtu3_pwm_request by calling rz_mtu3_request_channel()
* Simplified rz_mtu3_pwm_free by calling rz_mtu3_release_channel()v6->v7:
* Added channel specific mutex to avoid races between child devices (for eg: pwm and counter).
* Added rz_mtu3_shared_reg_update_bit() to update bits.
* Replaced sysfs variable "long_word_access_ctrl_mode->cascade_enable"
* Updated Kernel version in sysfs Documentation
* Updated commit description for counter driver
* Added Register descriptions
* Opimized size of cache variable by using union
* Used test_bit() in rz_mtu3_is_counter_invalid()
* Replaced val->timer_mode in rz_mtu3_count_function_{read,write}
* Added TODO comment phase3 and phase5 modes.
* replaced if-else with ternary expression in rz_mtu3_count_direction_read()
* Used switch statement in rz_mtu3_count_ceiling_read to consistent with write
* Provided default case for all switch statements.
* Add mutex lock for avoiding races with other devices and counter
* Updated comments in rz_mtu3_action_read()
* Replaced COUNTER_COMP_DEVICE_BOOL->COUNTER_COMP_DEVICE_BOOL for cascade_enable
* Replaced RZ_MTU3_GET_HW_CH->rz_mtu3_get_hw_ch
* Added rz_mtu3_get_ch() to get channels
* used rz_mtu3_shared_reg_update_bit for cascade_enable and selecting phase input clock.
* Added rz_mtu3_is_counter_invalid() check in rz_mtu3_count_ceiling_read()
* Added channel specific mutex lock to avoid race between counter device and rz_mtu3_pwm_{request,free}
* Added pm_runtime_resume_and_get in rz_mtu3_pwm_enable()
* Added pm_runtime_put_sync in rz_mtu3_pwm_disable()
* Updated rz_mtu3_pwm_config()
* Updated rz_mtu3_pwm_apply()v5->v6:
* Added Rb tag from Rob and Krzysztof for the binding patch.
* Updated commit and KConfig description for the driver patches
* Selected MFD_CORE to avoid build error if CONFIG_MFD_CORE not set.
* Improved error handling in core driver's probe().
* Fixed RZ_MTU3_GET_HW_CH Macro for argument reuse 'id' -
possible side-effects?
* Replaced SET_RUNTIME_PM_OPS->DEFINE_RUNTIME_DEV_PM_OPS and removed __maybe_unused from suspend/resume()
* Replaced dev_get_drvdata from rz_mtu3_pwm_pm_disable()
* Sorted header files for all driver files.v4->v5:
* Modelled as timer bindings.
* Fixed the typo in bindings.
* Moved core driver from MFD to timer
* Child devices instatiated using mfd_add_devices()
* Documented sysfs entries external_input_phase_clock_select and long_word_access_ctrl_mode.
* Updated the Kconfig with SoC vendor name
* Introduced rz_mtu3_is_counter_invalid()
* replaced pointer to an array of struct rz_mtu3_channel with
a simple pointer to struct rz_mtu3_channel.
* Added long_word_access_ctrl_mode sysfs entry for 16-bit and 32-bit access
* Added external_input_phase_clock_select sysfs entry for
selecting input clocks.
* used preprocessor defines represent SIGNAL_{A,B,C,D}_ID instead of signal ids.v3->v4:
* Dropped counter and pwm compatibeles as they don't have any resources.
* Made rz-mtu3 as pwm provider.
* Updated the example and description.
* A single driver that registers both the counter and the pwm functionalities that binds against "renesas,rz-mtu3".
* Moved PM handling from child devices to here.
* replaced include/linux/mfd/rz-mtu3.h->drivers/mfd/rz-mtu3.h
* Removed "remove" callback from mfd driver
* There is no resource associated with "rz-mtu3-counter" and "rz-mtu3-pwm" compatible and moved the code to mfd subsystem as it binds against "rz-mtu".
* Removed struct platform_driver rz_mtu3_cnt_driver.
* Removed struct platform_driver rz_mtu3_pwm_driver.
* Updated commit description
* Updated Kconfig description
* Added macros RZ_MTU3_16_BIT_MTU{1,2}_CH for MTU1 and MTU2 channels
* Added RZ_MTU3_GET_HW_CH macro for getting channel ID.
* replaced priv->ch[id]->priv->ch[0] in rz_mtu3_count_read()
* Cached counter max values
* replaced cnt->tsr in rz_mtu3_count_direction_read()
* Added comments for RZ_MTU3_TCR_CCLR_NONE
* Replaced if with switch in rz_mtu3_initialize_counter() and rz_mtu3_count_ceiling_write()
* Added locks in initialize, terminate and enable_read to prevent races.
* Updated rz_mtu3_action_read to take care of MTU2 signals.
* Added separate distinct array for each group of Synapse.
* Moved pm handling to parent.v2->v3:
* Dropped counter bindings and integrated with mfd as it has only one property.
* Removed "#address-cells" and "#size-cells" as it do not have children with unit addresses.
* Removed quotes from counter and pwm.
* Provided full path for pwm bindings.
* Updated the binding example.
* removed unwanted header files
* Added LUT for 32 bit registers as it needed for 32-bit cascade counting.
* Exported 32 bit read/write functions.
* Modelled as a counter device supporting 3 counters(2 16-bit and 32-bit)
* Add kernel-doc comments to document struct rz_mtu3_cnt
* Removed mmio variable from struct rz_mtu3_cnt
* Removed cnt local variable from rz_mtu3_count_read()
* Replaced -EINVAL->-ERANGE for out of range error conditions.
* Removed explicit cast from write functions.
* Removed local variable val from rz_mtu3_count_ceiling_read()
* Added lock for RMW for counter/ceiling updates.
* Added different synapses for counter0 and counter{1,2}
* Used ARRAY for assigning num_counts.
* Added PM runtime for managing clocks.
* Add MODULE_IMPORT_NS(COUNTER) to import the COUNTER namespace.
RFC->v2:
* replaced devm_reset_control_get->devm_reset_control_get_exclusive
* Dropped 'bindings' from the binding title
* Updated the binding example
* Added additionalProperties: false for counter bindings
* Squashed all the binding patches
* Modelled as a single counter device providing both 16-bit and 32-bit phase counting modes
* Modelled as a single pwm device for supporting different pwm modes.
* Moved counter and pwm bindings to respective subsystems.
Logs:
root@smarc-rzg2l:~# /mtu_test.sh #### Zero duty cycle ### #### decrement Period ### #### Increment Period ### #### decrement duty cycle ### #### Increment duty cycle ### ### Unbind the PWM driver#### ### Bind the PWM driver#### Positive counting cascade_counts_enable is 0 #### Ch0 count 0 2 8 13 18 23 28 34 38 44 49 3 8 13 19 24 29 34 39 45 #### Ch1 count #### Select Phase clock Phase clock MTCLKA-MTCLKB 1 6 11 16 1 5 11 16 0 5 10 16 20 5 10 15 20 4 10 14 #### Select Phase clock Phase clock MTCLKA-MTCLKB cascade_counts_enable is 1 #### Ch2 count 0 5 10 16 21 26 31 36 42 46 52 57 62 67 72 78 83 88 93 98 ### Unbind the counter driver#### ### Bind the counter driver#### ### Unbind the PWM driver#### ### Bind the PWM driver#### ### Unbind the Core driver#### ### Bind the Core driver#### root@smarc-rzg2l:~#
Biju Das (6):
dt-bindings: timer: Document RZ/G2L MTU3a bindings
mfd: Add Renesas RZ/G2L MTU3a core driver
Documentation: ABI: sysfs-bus-counter: add cascade_counts_enable and
external_input_phase_clock_select
counter: Add Renesas RZ/G2L MTU3a counter driver
MAINTAINERS: Add entries for Renesas RZ/G2L MTU3a counter driver
pwm: Add Renesas RZ/G2L MTU3a PWM driver
Documentation/ABI/testing/sysfs-bus-counter | 32 + .../bindings/timer/renesas,rz-mtu3.yaml | 302 ++++++ MAINTAINERS | 8 + drivers/counter/Kconfig | 11 + drivers/counter/Makefile | 1 + drivers/counter/rz-mtu3-cnt.c | 902 ++++++++++++++++++ drivers/mfd/Kconfig | 10 + drivers/mfd/Makefile | 1 + drivers/mfd/rz-mtu3.c | 391 ++++++++ drivers/mfd/rz-mtu3.h | 147 +++ drivers/pwm/Kconfig | 11 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-rz-mtu3.c | 486 ++++++++++ include/linux/mfd/rz-mtu3.h | 257 +++++ 14 files changed, 2560 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml create mode 100644 drivers/counter/rz-mtu3-cnt.c create mode 100644 drivers/mfd/rz-mtu3.c create mode 100644 drivers/mfd/rz-mtu3.h create mode 100644 drivers/pwm/pwm-rz-mtu3.c create mode 100644 include/linux/mfd/rz-mtu3.h
Signature · 1 line
2.25.1
Biju Das
maintainerPATCH v15 1/6 dt-bindings: timer: Document RZ/G2L MTU3a bindings
The RZ/G2L multi-function timer pulse unit 3 (MTU3a) is embedded in the Renesas RZ/G2L family SoC's. It consists of eight 16-bit timer channels and one 32-bit timer channel. It supports the following functions
- Counter
- Timer
- PWM
---
Ref:
https://patchwork.kernel.org/project/linux-renesas-soc/patch/[email protected]/v14->v15:
* No change.v13->v14:
* No change.v12->V13:
* No change.v11->V12:
* No change.v10->v11:
* No changev9->v10:
* No changev8->v9:
* No changev7->v8:
* No changev6->v7:
* No changev5->v6:
* Added Rb tag from Rob and Krzysztof.v4->v5:
* Modelled as timer bindings.
* Fixed the typo.v3->v4:
* Dropped counter and pwm compatibeles as they don't have any resources.
* Made rz-mtu3 as pwm provider.
* Updated the example and description.v2->v3:
* Dropped counter bindings and integrated with mfd as it has only one property.
* Removed "#address-cells" and "#size-cells" as it do not have children with unit addresses.
* Removed quotes from counter and pwm.
* Provided full path for pwm bindings.
* Updated the example.v1->v2:
* Modelled counter and pwm as a single device that handles multiple channels.
* Moved counter and pwm bindings to respective subsystems
* Dropped 'bindings' from MFD binding title.
* Updated the example
* Changed the compatible names.
--- .../bindings/timer/renesas,rz-mtu3.yaml | 302 ++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml
Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml new file +302 -0
@@ -0,0 +1,302 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/timer/renesas,rz-mtu3.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas RZ/G2L Multi-Function Timer Pulse Unit 3 (MTU3a) + +maintainers: + - Biju Das <[email protected]> + +description: | + This hardware block consists of eight 16-bit timer channels and one + 32- bit timer channel. It supports the following specifications: + - Pulse input/output: 28 lines max. + - Pulse input 3 lines + - Count clock 11 clocks for each channel (14 clocks for MTU0, 12 clocks + for MTU2, and 10 clocks for MTU5, four clocks for MTU1-MTU2 combination + (when LWA = 1)) + - Operating frequency Up to 100 MHz + - Available operations [MTU0 to MTU4, MTU6, MTU7, and MTU8] + - Waveform output on compare match + - Input capture function (noise filter setting available) + - Counter-clearing operation + - Simultaneous writing to multiple timer counters (TCNT) + (excluding MTU8). + - Simultaneous clearing on compare match or input capture + (excluding MTU8). + - Simultaneous input and output to registers in synchronization with + counter operations (excluding MTU8). + - Up to 12-phase PWM output in combination with synchronous operation + (excluding MTU8) + - [MTU0 MTU3, MTU4, MTU6, MTU7, and MTU8] + - Buffer operation specifiable + - [MTU1, MTU2] + - Phase counting mode can be specified independently + - 32-bit phase counting mode can be specified for interlocked operation + of MTU1 and MTU2 (when TMDR3.LWA = 1) + - Cascade connection operation available + - [MTU3, MTU4, MTU6, and MTU7] + - Through interlocked operation of MTU3/4 and MTU6/7, the positive and + negative signals in six phases (12 phases in total) can be output in + complementary PWM and reset-synchronized PWM operation. + - In complementary PWM mode, values can be transferred from buffer + registers to temporary registers at crests and troughs of the timer- + counter values or when the buffer registers (TGRD registers in MTU4 + and MTU7) are written to. + - Double-buffering selectable in complementary PWM mode. + - [MTU3 and MTU4] + - Through interlocking with MTU0, a mode for driving AC synchronous + motors (brushless DC motors) by using complementary PWM output and + reset-synchronized PWM output is settable and allows the selection + of two types of waveform output (chopping or level). + - [MTU5] + - Capable of operation as a dead-time compensation counter. + - [MTU0/MTU5, MTU1, MTU2, and MTU8] + - 32-bit phase counting mode specifiable by combining MTU1 and MTU2 and + through interlocked operation with MTU0/MTU5 and MTU8. + - Interrupt-skipping function + - In complementary PWM mode, interrupts on crests and troughs of counter + values and triggers to start conversion by the A/D converter can be + skipped. + - Interrupt sources: 43 sources. + - Buffer operation: + - Automatic transfer of register data (transfer from the buffer + register to the timer register). + - Trigger generation + - A/D converter start triggers can be generated + - A/D converter start request delaying function enables A/D converter + to be started with any desired timing and to be synchronized with + PWM output. + - Low power consumption function + - The MTU3a can be placed in the module-stop state. + + There are two phase counting modes. 16-bit phase counting mode in which + MTU1 and MTU2 operate independently, and cascade connection 32-bit phase + counting mode in which MTU1 and MTU2 are cascaded. + + In phase counting mode, the phase difference between two external input + clocks is detected and the corresponding TCNT is incremented or + decremented. + The below counters are supported + count0 - MTU1 16-bit phase counting + count1 - MTU2 16-bit phase counting + count2 - MTU1+ MTU2 32-bit phase counting + + The module supports PWM mode{1,2}, Reset-synchronized PWM mode and + complementary PWM mode{1,2,3}. + + In complementary PWM mode, six positive-phase and six negative-phase PWM + waveforms (12 phases in total) with dead time can be output by + combining MTU{3,4} and MTU{6,7}. + + The below pwm channels are supported in pwm mode 1. + pwm0 - MTU0.MTIOC0A PWM mode 1 + pwm1 - MTU0.MTIOC0C PWM mode 1 + pwm2 - MTU1.MTIOC1A PWM mode 1 + pwm3 - MTU2.MTIOC2A PWM mode 1 + pwm4 - MTU3.MTIOC3A PWM mode 1 + pwm5 - MTU3.MTIOC3C PWM mode 1 + pwm6 - MTU4.MTIOC4A PWM mode 1 + pwm7 - MTU4.MTIOC4C PWM mode 1 + pwm8 - MTU6.MTIOC6A PWM mode 1 + pwm9 - MTU6.MTIOC6C PWM mode 1 + pwm10 - MTU7.MTIOC7A PWM mode 1 + pwm11 - MTU7.MTIOC7C PWM mode 1 + +properties: + compatible: + items: + - enum: + - renesas,r9a07g044-mtu3 # RZ/G2{L,LC} + - renesas,r9a07g054-mtu3 # RZ/V2L + - const: renesas,rz-mtu3 + + reg: + maxItems: 1 + + interrupts: + items: + - description: MTU0.TGRA input capture/compare match + - description: MTU0.TGRB input capture/compare match + - description: MTU0.TGRC input capture/compare match + - description: MTU0.TGRD input capture/compare match + - description: MTU0.TCNT overflow + - description: MTU0.TGRE compare match + - description: MTU0.TGRF compare match + - description: MTU1.TGRA input capture/compare match + - description: MTU1.TGRB input capture/compare match + - description: MTU1.TCNT overflow + - description: MTU1.TCNT underflow + - description: MTU2.TGRA input capture/compare match + - description: MTU2.TGRB input capture/compare match + - description: MTU2.TCNT overflow + - description: MTU2.TCNT underflow + - description: MTU3.TGRA input capture/compare match + - description: MTU3.TGRB input capture/compare match + - description: MTU3.TGRC input capture/compare match + - description: MTU3.TGRD input capture/compare match + - description: MTU3.TCNT overflow + - description: MTU4.TGRA input capture/compare match + - description: MTU4.TGRB input capture/compare match + - description: MTU4.TGRC input capture/compare match + - description: MTU4.TGRD input capture/compare match + - description: MTU4.TCNT overflow/underflow + - description: MTU5.TGRU input capture/compare match + - description: MTU5.TGRV input capture/compare match + - description: MTU5.TGRW input capture/compare match + - description: MTU6.TGRA input capture/compare match + - description: MTU6.TGRB input capture/compare match + - description: MTU6.TGRC input capture/compare match + - description: MTU6.TGRD input capture/compare match + - description: MTU6.TCNT overflow + - description: MTU7.TGRA input capture/compare match + - description: MTU7.TGRB input capture/compare match + - description: MTU7.TGRC input capture/compare match + - description: MTU7.TGRD input capture/compare match + - description: MTU7.TCNT overflow/underflow + - description: MTU8.TGRA input capture/compare match + - description: MTU8.TGRB input capture/compare match + - description: MTU8.TGRC input capture/compare match + - description: MTU8.TGRD input capture/compare match + - description: MTU8.TCNT overflow + - description: MTU8.TCNT underflow + + interrupt-names: + items: + - const: tgia0 + - const: tgib0 + - const: tgic0 + - const: tgid0 + - const: tgiv0 + - const: tgie0 + - const: tgif0 + - const: tgia1 + - const: tgib1 + - const: tgiv1 + - const: tgiu1 + - const: tgia2 + - const: tgib2 + - const: tgiv2 + - const: tgiu2 + - const: tgia3 + - const: tgib3 + - const: tgic3 + - const: tgid3 + - const: tgiv3 + - const: tgia4 + - const: tgib4 + - const: tgic4 + - const: tgid4 + - const: tgiv4 + - const: tgiu5 + - const: tgiv5 + - const: tgiw5 + - const: tgia6 + - const: tgib6 + - const: tgic6 + - const: tgid6 + - const: tgiv6 + - const: tgia7 + - const: tgib7 + - const: tgic7 + - const: tgid7 + - const: tgiv7 + - const: tgia8 + - const: tgib8 + - const: tgic8 + - const: tgid8 + - const: tgiv8 + - const: tgiu8 + + clocks: + maxItems: 1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + "#pwm-cells": + const: 2 + +required: + - compatible + - reg + - interrupts + - interrupt-names + - clocks + - power-domains + - resets + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/r9a07g044-cpg.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + mtu3: timer@10001200 { + compatible = "renesas,r9a07g044-mtu3", "renesas,rz-mtu3"; + reg = <0x10001200 0xb00>; + interrupts = <GIC_SPI 170 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 172 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 173 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 174 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 175 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 176 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 177 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 178 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 179 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 180 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 181 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 182 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 183 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 184 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 185 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 186 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 187 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 188 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 189 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 190 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 191 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 192 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 194 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 196 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 198 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 199 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 200 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 201 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 202 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 203 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 204 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 205 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 206 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 207 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 208 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 209 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 210 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 211 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 212 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 213 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "tgia0", "tgib0", "tgic0", "tgid0", "tgiv0", "tgie0", + "tgif0", + "tgia1", "tgib1", "tgiv1", "tgiu1", + "tgia2", "tgib2", "tgiv2", "tgiu2", + "tgia3", "tgib3", "tgic3", "tgid3", "tgiv3", + "tgia4", "tgib4", "tgic4", "tgid4", "tgiv4", + "tgiu5", "tgiv5", "tgiw5", + "tgia6", "tgib6", "tgic6", "tgid6", "tgiv6", + "tgia7", "tgib7", "tgic7", "tgid7", "tgiv7", + "tgia8", "tgib8", "tgic8", "tgid8", "tgiv8", "tgiu8"; + clocks = <&cpg CPG_MOD R9A07G044_MTU_X_MCK_MTU3>; + power-domains = <&cpg>; + resets = <&cpg R9A07G044_MTU_X_PRESET_MTU3>; + #pwm-cells = <2>; + };
Signature · 1 line
2.25.1
Re: [PATCH v15 1/6] dt-bindings: timer: Document RZ/G2L MTU3a bindings
Quoted 55 lines · Biju Das
The RZ/G2L multi-function timer pulse unit 3 (MTU3a) is embedded in the Renesas RZ/G2L family SoC's. It consists of eight 16-bit timer channels and one 32-bit timer channel. It supports the following functions
- Counter
- Timer
- PWMSigned-off-by Biju Das <[email protected]>Reviewed-by Krzysztof Kozlowski <[email protected]>Reviewed-by Rob Herring <[email protected]>---
Ref:
https://patchwork.kernel.org/project/linux-renesas-soc/patch/[email protected]/v14->v15:
* No change.v13->v14:
* No change.v12->V13:
* No change.v11->V12:
* No change.v10->v11:
* No changev9->v10:
* No changev8->v9:
* No changev7->v8:
* No changev6->v7:
* No changev5->v6:
* Added Rb tag from Rob and Krzysztof.v4->v5:
* Modelled as timer bindings.
* Fixed the typo.v3->v4:
* Dropped counter and pwm compatibeles as they don't have any resources.
* Made rz-mtu3 as pwm provider.
* Updated the example and description.v2->v3:
* Dropped counter bindings and integrated with mfd as it has only one property.
* Removed "#address-cells" and "#size-cells" as it do not have children with unit addresses.
* Removed quotes from counter and pwm.
* Provided full path for pwm bindings.
* Updated the example.v1->v2:
* Modelled counter and pwm as a single device that handles multiple channels.
* Moved counter and pwm bindings to respective subsystems
* Dropped 'bindings' from MFD binding title.
* Updated the example
* Changed the compatible names.
Quoted 4 lines
--- .../bindings/timer/renesas,rz-mtu3.yaml | 302 ++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml
Applied, thanks
--
Lee Jones [李琼斯]
Biju Das
maintainerPATCH v15 2/6 mfd: Add Renesas RZ/G2L MTU3a core driver
In reply to Biju DasThe RZ/G2L multi-function timer pulse unit 3 (MTU3a) is embedded in the Renesas RZ/G2L family SoCs. It consists of eight 16-bit timer channels and one 32-bit timer channel. It supports the following functions
- Counter
- Timer
- PWM
The 8/16/32 bit registers are mixed in each channel.
Add MTU3a core driver for RZ/G2L SoC. The core driver shares the clk and channel register access for the other child devices like Counter, PWM and Clock event.
---
Ref:
https://patchwork.kernel.org/project/linux-renesas-soc/patch/[email protected]/v14->v15:
* Moved PWM register definitions from pwm-rz-mtu3.c to the header file.v13->v14:
* Added helper macros for initializing 8/16/32 channel reg offset table in "drivers/mfd/rz-mtu3.h"
* Replaced "off"->offset in read_write()
* Replaced __LINUX_RZ_MTU3_H__->__MFD_RZ_MTU3_H__
* Added header file device.h and mutex.h
* Updated rz_mtu3_request_channel()
* Replaced channel_index->channel_number in struct rz_mtu3_channel
* Dropped redundant comments.
* Renamed channel number macros from RZ_MTU*->RZ_MTU3_CHAN_*
* Added core driver specific private data in struct rz_mtu3 and updated the comments. This replaces mmio from struct rz_mtu3.
* Started using actual offset in channel reg table and removed ch_reg_offsets table Also simplified the code 8/16/32 bits read_write() and removed base from struct rz_mtu3_channel.
* Simplified rz_mtu3_start_stop_ch()/rz_mtu3_is_enabled() by adding helper functions rz_mtu3_get_tstr_offset()/rz_mtu3_get_tstr_bit_pos().v12->v13:
* Moved RZ_MTU3_TMDR1_* macros from pwm driver to rz-mtu3.h.v11->v2:
* Moved the core driver from timer to MFD.
* Moved header fine from clocksource/rz-mtu3.h->linux/mfd/rz-mtu3.h
* Removed Select MFD_CORE option from config.v10->v11:
* No change.v9->v10:
* No change.v8->v9:
* No change.v7->v8:
* Add locking for RMW on rz_mtu3_shared_reg_update_bit()
* Replaced enum rz_mtu3_functions with channel busy flag
* Added API for request and release a channel.v6->v7:
* Added channel specific mutex to avoid races between child devices (for eg: pwm and counter)
* Added rz_mtu3_shared_reg_update_bit() to update bit.v5->v6:
* Updated commit and KConfig description
* Selected MFD_CORE to avoid build error if CONFIG_MFD_CORE not set.
* Improved error handling in probe().
* Updated MODULE_DESCRIPTION and title.v4->v5:
* Moved core driver from MFD to timer
* Child devices instatiated using mfd_add_devices()v3->v4:
* A single driver that registers both the counter and the pwm functionalities that binds against "renesas,rz-mtu3".
* Moved PM handling from child devices to here.
* replaced include/linux/mfd/rz-mtu3.h->drivers/mfd/rz-mtu3.h
* Removed "remove" callbackv2->v3:
* removed unwanted header files
* Added LUT for 32 bit registers as it needed for 32-bit cascade counting.
* Exported 32 bit read/write functions.v1->v2:
* Changed the compatible name
* Replaced devm_reset_control_get->devm_reset_control_get_exclusive
* Renamed function names rzg2l_mtu3->rz_mtu3 as this is generic IP
in RZ family SoC's.
--- drivers/mfd/Kconfig | 10 + drivers/mfd/Makefile | 1 + drivers/mfd/rz-mtu3.c | 391 ++++++++++++++++++++++++++++++++++++ drivers/mfd/rz-mtu3.h | 147 ++++++++++++++ include/linux/mfd/rz-mtu3.h | 257 ++++++++++++++++++++++++ 5 files changed, 806 insertions(+) create mode 100644 drivers/mfd/rz-mtu3.c create mode 100644 drivers/mfd/rz-mtu3.h create mode 100644 include/linux/mfd/rz-mtu3.h
drivers/mfd/Kconfig +10 -0
@@ -1315,6 +1315,16 @@ config MFD_SC27XX_PMIC This driver provides common support for accessing the SC27xx PMICs, and it also adds the irq_chip parts for handling the PMIC chip events. +config RZ_MTU3 + bool "Renesas RZ/G2L MTU3a core driver" + depends on (ARCH_RZG2L && OF) || COMPILE_TEST + help + Select this option to enable Renesas RZ/G2L MTU3a core driver for + the Multi-Function Timer Pulse Unit 3 (MTU3a) hardware available + on SoCs from Renesas. The core driver shares the clk and channel + register access for the other child devices like Counter, PWM, + Clock Source, and Clock event. + config ABX500_CORE bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" depends on ARCH_U8500 || COMPILE_TEST
drivers/mfd/Makefile +1 -0
@@ -174,6 +174,7 @@ pcf50633-objs := pcf50633-core.o pcf50633-irq.o obj-$(CONFIG_MFD_PCF50633) += pcf50633.o obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o +obj-$(CONFIG_RZ_MTU3) += rz-mtu3.o obj-$(CONFIG_ABX500_CORE) += abx500-core.o obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o # ab8500-core need to come after db8500-prcmu (which provides the channel)
drivers/mfd/rz-mtu3.c new file +391 -0
391 lines not on this page · raw message
drivers/mfd/rz-mtu3.h new file +147 -0
147 lines not on this page · raw message
include/linux/mfd/rz-mtu3.h new file +257 -0
257 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [PATCH v15 2/6] mfd: Add Renesas RZ/G2L MTU3a core driver
Quoted 80 lines · Biju Das
The RZ/G2L multi-function timer pulse unit 3 (MTU3a) is embedded in the Renesas RZ/G2L family SoCs. It consists of eight 16-bit timer channels and one 32-bit timer channel. It supports the following functions
- Counter
- Timer
- PWMThe 8/16/32 bit registers are mixed in each channel.
Add MTU3a core driver for RZ/G2L SoC. The core driver shares the clk and channel register access for the other child devices like Counter, PWM and Clock event.
Signed-off-by Biju Das <[email protected]>---
Ref:
https://patchwork.kernel.org/project/linux-renesas-soc/patch/[email protected]/v14->v15:
* Moved PWM register definitions frompwm-rz-mtu3.cto the header file.v13->v14:
* Added helper macros for initializing 8/16/32 channel reg offset table in "drivers/mfd/rz-mtu3.h"
* Replaced "off"->offset inread_write()
* Replaced__LINUX_RZ_MTU3_H__->__MFD_RZ_MTU3_H__
* Added header filedevice.handmutex.h
* Updatedrz_mtu3_request_channel()
* Replacedchannel_index->channel_numberin structrz_mtu3_channel
* Dropped redundant comments.
* Renamed channel number macros from RZ_MTU*->RZ_MTU3_CHAN_*
* Added core driver specific private data in structrz_mtu3and updated the comments. This replaces mmio from structrz_mtu3.
* Started using actual offset in channel reg table and removedch_reg_offsetstable Also simplified the code 8/16/32 bitsread_write()and removed base from structrz_mtu3_channel.
* Simplified rz_mtu3_start_stop_ch()/rz_mtu3_is_enabled() by adding helper functions rz_mtu3_get_tstr_offset()/rz_mtu3_get_tstr_bit_pos().v12->v13:
* Moved RZ_MTU3_TMDR1_* macros from pwm driver torz-mtu3.h.v11->v2:
* Moved the core driver from timer to MFD.
* Moved header fine from clocksource/rz-mtu3.h->linux/mfd/rz-mtu3.h
* Removed SelectMFD_COREoption from config.v10->v11:
* No change.v9->v10:
* No change.v8->v9:
* No change.v7->v8:
* Add locking for RMW onrz_mtu3_shared_reg_update_bit()
* Replaced enumrz_mtu3_functionswith channel busy flag
* Added API for request and release a channel.v6->v7:
* Added channel specific mutex to avoid races between child devices (for eg: pwm and counter)
* Addedrz_mtu3_shared_reg_update_bit()to update bit.v5->v6:
* Updated commit and KConfig description
* SelectedMFD_COREto avoid build error ifCONFIG_MFD_COREnot set.
* Improved error handling inprobe().
* UpdatedMODULE_DESCRIPTIONand title.v4->v5:
* Moved core driver from MFD to timer
* Child devices instatiated usingmfd_add_devices()v3->v4:
* A single driver that registers both the counter and the pwm functionalities that binds against "renesas,rz-mtu3".
* Moved PM handling from child devices to here.
* replaced include/linux/mfd/rz-mtu3.h->drivers/mfd/rz-mtu3.h
* Removed "remove" callbackv2->v3:
* removed unwanted header files
* Added LUT for 32 bit registers as it needed for 32-bit cascade counting.
* Exported 32 bit read/write functions.v1->v2:
* Changed the compatible name
* Replaceddevm_reset_control_get->devm_reset_control_get_exclusive
* Renamed function namesrzg2l_mtu3->rz_mtu3as this is generic IP
in RZ family SoC's.
Quoted 10 lines
--- drivers/mfd/Kconfig | 10 + drivers/mfd/Makefile | 1 + drivers/mfd/rz-mtu3.c | 391 ++++++++++++++++++++++++++++++++++++ drivers/mfd/rz-mtu3.h | 147 ++++++++++++++ include/linux/mfd/rz-mtu3.h | 257 ++++++++++++++++++++++++ 5 files changed, 806 insertions(+) create mode 100644 drivers/mfd/rz-mtu3.c create mode 100644 drivers/mfd/rz-mtu3.h create mode 100644 include/linux/mfd/rz-mtu3.h
Applied, thanks
--
Lee Jones [李琼斯]
Biju Das
maintainerPATCH v15 3/6 Documentation: ABI: sysfs-bus-counter: add cascade_counts_enable and external_input_phase_clock_select
In reply to Biju DasThis commit adds cascade_counts_enable and external_input_phase_ clock_select items to counter ABI file.
(e.g. for Renesas MTU3 hardware used for phase counting).
---v14->v15:
* No change.v13->v14:
* No change.v12->v13:
* Updated kernel version from 6.3->6.4 as it is too late.v11->v12:
* No changev10->v11:
* No change.v9->v10:
* Added Rb tag from William Breathitt Grayv8->v9:
* Added available blocks for external_input_phase_clock_select_available
* Removed the "This attribute" from the external_input_phase_clock_select description, and capitalize the word "counter" from description.
* Removed the "This attribute" from the cascade_counts_enable description, and capitalize "counts" and "counter"
* Moved these device-level configuration blocks to top of the file.v7->v8:
* Replaced cascade_enable->cascade_counts_enable
* Updated commit header and description
* Added external_input_phase_clock_select_available entry for driver- specific enum attribute and created a new entry block for it.
* Add a line stating cascade_counts_enable is a boolean attribute.
* Added missing 'component_id' suffix.v6->v7:
* Replaced long_word_access_ctrl_mode->cascade_enable
* Updated Kernel versionv5->v6:
* No change
v5:
* New patch
--- Documentation/ABI/testing/sysfs-bus-counter | 32 +++++++++++++++++++++ 1 file changed, 32 insertions(+)
Documentation/ABI/testing/sysfs-bus-counter +32 -0
@@ -1,3 +1,33 @@ +What: /sys/bus/counter/devices/counterX/cascade_counts_enable +KernelVersion: 6.4 +Contact: [email protected] +Description: + Indicates the cascading of Counts on Counter X. + + Valid attribute values are boolean. + +What: /sys/bus/counter/devices/counterX/external_input_phase_clock_select +KernelVersion: 6.4 +Contact: [email protected] +Description: + Selects the external clock pin for phase counting mode of + Counter X. + + MTCLKA-MTCLKB: + MTCLKA and MTCLKB pins are selected for the external + phase clock. + + MTCLKC-MTCLKD: + MTCLKC and MTCLKD pins are selected for the external + phase clock. + +What: /sys/bus/counter/devices/counterX/external_input_phase_clock_select_available +KernelVersion: 6.4 +Contact: [email protected] +Description: + Discrete set of available values for the respective device + configuration are listed in this file. + What: /sys/bus/counter/devices/counterX/countY/count KernelVersion: 5.2 Contact: [email protected]
@@ -215,6 +245,8 @@ Contact: [email protected] Description: This attribute indicates the number of overflows of count Y. +What: /sys/bus/counter/devices/counterX/cascade_counts_enable_component_id +What: /sys/bus/counter/devices/counterX/external_input_phase_clock_select_component_id What: /sys/bus/counter/devices/counterX/countY/capture_component_id What: /sys/bus/counter/devices/counterX/countY/ceiling_component_id What: /sys/bus/counter/devices/counterX/countY/floor_component_id
Signature · 1 line
2.25.1
Re: [PATCH v15 3/6] Documentation: ABI: sysfs-bus-counter: add cascade_counts_enable and external_input_phase_clock_select
Quoted 40 lines · Biju Das
This commit adds
cascade_counts_enableandexternal_input_phase_clock_selectitems to counter ABI file.
(e.g. for Renesas MTU3 hardware used for phase counting).Signed-off-by Biju Das <[email protected]>Reviewed-by William Breathitt Gray <[email protected]>---
v14->v15:
* No change.v13->v14:
* No change.v12->v13:
* Updated kernel version from 6.3->6.4 as it is too late.v11->v12:
* No changev10->v11:
* No change.v9->v10:
* Added Rb tag from William Breathitt Grayv8->v9:
* Added available blocks forexternal_input_phase_clock_select_available
* Removed the "This attribute" from theexternal_input_phase_clock_selectdescription, and capitalize the word "counter" from description.
* Removed the "This attribute" from thecascade_counts_enabledescription, and capitalize "counts" and "counter"
* Moved these device-level configuration blocks to top of the file.v7->v8:
* Replacedcascade_enable->cascade_counts_enable
* Updated commit header and description
* Addedexternal_input_phase_clock_select_availableentry for driver- specific enum attribute and created a new entry block for it.
* Add a line statingcascade_counts_enableis a boolean attribute.
* Added missing 'component_id' suffix.v6->v7:
* Replacedlong_word_access_ctrl_mode->cascade_enable
* Updated Kernel versionv5->v6:
* No change
v5:
* New patch
Quoted 3 lines
--- Documentation/ABI/testing/sysfs-bus-counter | 32 +++++++++++++++++++++ 1 file changed, 32 insertions(+)
Applied, thanks
--
Lee Jones [李琼斯]
Biju Das
maintainerPATCH v15 4/6 counter: Add Renesas RZ/G2L MTU3a counter driver
In reply to Biju DasAdd RZ/G2L MTU3a counter driver. This IP supports the following phase counting modes on MTU1 and MTU2 channels
1) 16-bit phase counting modes on MTU1 and MTU2 channels.
2) 32-bit phase counting mode by cascading MTU1 and MTU2 channels.
This patch adds 3 counter value channels.
count0: 16-bit phase counter value channel on MTU1
count1: 16-bit phase counter value channel on MTU2
count2: 32-bit phase counter value channel by cascading
MTU1 and MTU2 channels.
The external input phase clock pin for the counter value channels are as follows:
count0: "MTCLKA-MTCLKB"
count1: "MTCLKA-MTCLKB" or "MTCLKC-MTCLKD"
count2: "MTCLKA-MTCLKB" or "MTCLKC-MTCLKD"
Use the sysfs variable "external_input_phase_clock_select" to select the external input phase clock pin and "cascade_counts_enable" to enable/ disable cascading of channels.
---v14->v15:
* No change.v13->v14:
* Added Acked-by tag from William Breathitt Gray
* Replaced RZ_MTU1->RZ_MTU3_CHAN_1 and retained the Rb/ack tag as it is trivial change.v12->v13:
* No change.v11->v12:
* Updated header file to <linux/mfd/rz-mtu3.h> as core driver is moved to MFD.v10->v11:
* Added Rb tag from William Breathitt Gray
* Replaced count2 channel name from "combined"->"cascaded", as channels are cascaded
* Simplified the locking by adding the helper functions rz_mtu3_lock_if_counter_is_valid, rz_mtu3_lock_if_count_is_enabled, and rz_mtu3_lock_if_ch0_is_enabled.v9->v10:
* Added helper function for rz_mtu3_count_{action,function}_read
* Added priv->lock in rz_mtu3_count_function_read and rz_mtu3_count_ direction_read.
* Added ch->is_busy check for rz_mtu3_action_read()
* Added rz_mtu3_is_ch0_enabled() for device specific sysfs variables.
* Added ch->is_busy check for device specific sysfs variables.v8->v9:
* Added count_is_enabled variable to struct rz_mtu3_cnt
* Added check for ch->is_busy and count_is_enabled before every Counter callback to ensure we do not try to access a busy channel used by other subsystem(eg: pwm).
* Removed id parameter from rz_mtu3_32bit_cnt_setting()
* Made definition of rz_mtu3_get_ch() in single line.
* Replaced break->return in rz_mtu3_32bit_cnt_setting(), rz_mtu3_count_function_read() and rz_mtu3_initialize_counter() and removed redundant return 0.
* Simplified synapse signal check for rz_mtu3_action_read().v7->v8:
* Simplified rz_mtu3_initialize_counter by calling rz_mtu3_request_ channel() and release the acquired sibling channel in case of error.
* Simplified rz_mtu3_terminate_counter by calling rz_mtu3_release_ channel().
* Removed unused ceiling and ch_id from rz_mtu3_count_write()
* Replaced the error -EINVAL->-EBUSY for rz_mtu3_is_counter_invalid()
* Avoided race between rz_mtu3_count_{read, write} with rz_mtu3_ cascade_counts_enable_set() by adding locks and moved the lock before rz_mtu3_is_counter_invalid()
* Protected the rz_mtu3_count_ceiling_read() function with a lock to make sure the cascade operation mode doesn't not change and that the priv data structure accesses don't race when they are changed in the ceiling_write() callback.
* Added lock in rz_mtu3_cascade_enable_set() to make sure the other callbacks don't try to read the LWA state while updating LWA.
* Added lock in rz_mtu3_ext_input_phase_clock_select_set() to ensure the other callbacks don't try to read the PHCKSEL state while updating PHCKSEL.
* Added lock to avoid race between rz_mtu3_count_function_write() and rz_mtu3_action_read()
* Updated rz_mtu3_action_read to return 0, if Synapse is in COUNTER_SYNAPSE _ACTION_NONE state.
* Replaced sysfs variable cascade_enable->cascade_counts_enable
* Renamed rz_mtu3_cascade_enable_get->rz_mtu3_cascade_counts_enable_get
* Renamed rz_mtu3_cascade_enable_set->rz_mtu3_cascade_counts_enable_set
* Removed redundent ceiling assignment from rz_mtu3_count_ceiling_read()
* Removed unused ceiling and ch_id from rz_mtu3_count_write().v6->v7:
* Updated commit description
* Added Register descriptions
* Opimized size of cache variable by using union
* Used test_bit() in rz_mtu3_is_counter_invalid()
* Replaced val->timer_mode in rz_mtu3_count_function_{read,write}
* Added TODO comment phase3 and phase5 modes.
* replaced if-else with ternary expression in rz_mtu3_count_direction_read()
* Used switch statement in rz_mtu3_count_ceiling_read to consistent with write
* Provided default case for all switch statement.
* Add mutex lock for avoiding races with other devices
* Updated comments in rz_mtu3_action_read
* Replaced COUNTER_COMP_DEVICE_BOOL->COUNTER_COMP_DEVICE_BOOL for cascade_enable
* Replaced RZ_MTU3_GET_HW_CH->rz_mtu3_get_hw_ch
* Added rz_mtu3_get_ch() to get channels
* used rz_mtu3_shared_reg_update_bit for cascade_enable and selecting phase input clock.
* Added rz_mtu3_is_counter_invalid() check in rz_mtu3_count_ceiling_read()v5->v6:
* Updated KConfig and commit description
* Sorted header
* Fixed RZ_MTU3_GET_HW_CH Macro for argument reuse 'id' - possible side-effects?
* Replaced SET_RUNTIME_PM_OPS->DEFINE_RUNTIME_DEV_PM_OPS and removed __maybe_unused from suspend/resume()v4->v5:
* Updated the Kconfig with SoC vendor name
* Introduced rz_mtu3_is_counter_invalid()
* replaced pointer to an array of struct rz_mtu3_channel with
a simple pointer to struct rz_mtu3_channel.
* Added long_word_access_ctrl_mode sysfs entry for 16-bit and 32-bit access
* Added external_input_phase_clock_select sysfs entry for selecting input clocks.
* used preprocessor defines represent SIGNAL_{A,B,C,D}_ID instead of signal ids.v3->v4:
* There is no resource associated with "rz-mtu3-counter" compatible and moved the code to mfd subsystem as it binds against "rz-mtu".
* Removed struct platform_driver rz_mtu3_cnt_driver.
* Updated commit description
* Updated Kconfig description
* Added macros RZ_MTU3_16_BIT_MTU{1,2}_CH for MTU1 and MTU2 channels
* Added RZ_MTU3_GET_HW_CH macro for getting channel ID.
* replaced priv->ch[id]->priv->ch[0] in rz_mtu3_count_read()
* Cached counter max values
* replaced cnt->tsr in rz_mtu3_count_direction_read()
* Added comments for RZ_MTU3_TCR_CCLR_NONE
* Replaced if with switch in rz_mtu3_initialize_counter() and rz_mtu3_count_ceiling_write()
* Added locks in initialize, terminate and enable_read to prevent races.
* Updated rz_mtu3_action_read to take care of MTU2 signals.
* Added separate distinct array for each group of Synapse.
* Moved pm handling to parent.
v1->v3:
* Modelled as a counter device supporting 3 counters(2 16-bit and 32-bit)
* Add kernel-doc comments to document struct rz_mtu3_cnt
* Removed mmio variable from struct rz_mtu3_cnt
* Removed cnt local variable from rz_mtu3_count_read()
* Replaced -EINVAL->-ERANGE for out of range error conditions.
* Removed explicit cast from write functions.
* Removed local variable val from rz_mtu3_count_ceiling_read()
* Added lock for RMW for counter/ceiling updates.
* Added different synapses for counter0 and counter{1,2}
* Used ARRAY for assigning num_counts.
* Added PM runtime for managing clocks.
* Add MODULE_IMPORT_NS(COUNTER) to import the COUNTER namespace.
--- drivers/counter/Kconfig | 11 + drivers/counter/Makefile | 1 + drivers/counter/rz-mtu3-cnt.c | 902 ++++++++++++++++++++++++++++++++++ 3 files changed, 914 insertions(+) create mode 100644 drivers/counter/rz-mtu3-cnt.c
drivers/counter/Kconfig +11 -0
@@ -73,6 +73,17 @@ config MICROCHIP_TCB_CAPTURE To compile this driver as a module, choose M here: the module will be called microchip-tcb-capture. +config RZ_MTU3_CNT + tristate "Renesas RZ/G2L MTU3a counter driver" + depends on RZ_MTU3 || COMPILE_TEST + help + Enable support for MTU3a counter driver found on Renesas RZ/G2L alike + SoCs. This IP supports both 16-bit and 32-bit phase counting mode + support. + + To compile this driver as a module, choose M here: the + module will be called rz-mtu3-cnt. + config STM32_LPTIMER_CNT tristate "STM32 LP Timer encoder counter driver" depends on MFD_STM32_LPTIMER || COMPILE_TEST
drivers/counter/Makefile +1 -0
@@ -8,6 +8,7 @@ counter-y := counter-core.o counter-sysfs.o counter-chrdev.o obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o obj-$(CONFIG_INTERRUPT_CNT) += interrupt-cnt.o +obj-$(CONFIG_RZ_MTU3_CNT) += rz-mtu3-cnt.o obj-$(CONFIG_STM32_TIMER_CNT) += stm32-timer-cnt.o obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o obj-$(CONFIG_TI_EQEP) += ti-eqep.o
drivers/counter/rz-mtu3-cnt.c new file +902 -0
902 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [PATCH v15 4/6] counter: Add Renesas RZ/G2L MTU3a counter driver
Quoted 159 lines · Biju Das
Add RZ/G2L MTU3a counter driver. This IP supports the following phase counting modes on MTU1 and MTU2 channels
1) 16-bit phase counting modes on MTU1 and MTU2 channels.
2) 32-bit phase counting mode by cascading MTU1 and MTU2 channels.This patch adds 3 counter value channels.
count0: 16-bit phase counter value channel on MTU1
count1: 16-bit phase counter value channel on MTU2
count2: 32-bit phase counter value channel by cascading
MTU1 and MTU2 channels.The external input phase clock pin for the counter value channels are as follows:
count0: "MTCLKA-MTCLKB"
count1: "MTCLKA-MTCLKB" or "MTCLKC-MTCLKD"
count2: "MTCLKA-MTCLKB" or "MTCLKC-MTCLKD"Use the sysfs variable "
external_input_phase_clock_select" to select the external input phase clock pin and "cascade_counts_enable" to enable/ disable cascading of channels.Signed-off-by Biju Das <[email protected]>Reviewed-by William Breathitt Gray <[email protected]>---
v14->v15:
* No change.v13->v14:
* Added Acked-by tag from William Breathitt Gray
* ReplacedRZ_MTU1->RZ_MTU3_CHAN_1and retained the Rb/ack tag as it is trivial change.v12->v13:
* No change.v11->v12:
* Updated header file to <linux/mfd/rz-mtu3.h> as core driver is moved to MFD.v10->v11:
* Added Rb tag from William Breathitt Gray
* Replaced count2 channel name from "combined"->"cascaded", as channels are cascaded
* Simplified the locking by adding the helper functionsrz_mtu3_lock_if_counter_is_valid,rz_mtu3_lock_if_count_is_enabled, andrz_mtu3_lock_if_ch0_is_enabled.v9->v10:
* Added helper function for rz_mtu3_count_{action,function}_read
* Addedpriv->lockinrz_mtu3_count_function_readandrz_mtu3_count_direction_read.
* Addedch->is_busycheck forrz_mtu3_action_read()
* Addedrz_mtu3_is_ch0_enabled()for device specific sysfs variables.
* Addedch->is_busycheck for device specific sysfs variables.v8->v9:
* Addedcount_is_enabledvariable to structrz_mtu3_cnt
* Added check forch->is_busyandcount_is_enabledbefore every Counter callback to ensure we do not try to access a busy channel used by other subsystem(eg: pwm).
* Removed id parameter fromrz_mtu3_32bit_cnt_setting()
* Made definition ofrz_mtu3_get_ch()in single line.
* Replacedbreak->returninrz_mtu3_32bit_cnt_setting(),rz_mtu3_count_function_read()andrz_mtu3_initialize_counter()and removed redundant return 0.
* Simplified synapse signal check forrz_mtu3_action_read().v7->v8:
* Simplifiedrz_mtu3_initialize_counterby callingrz_mtu3_request_channel()and release the acquired sibling channel in case of error.
* Simplifiedrz_mtu3_terminate_counterby callingrz_mtu3_release_channel().
* Removed unused ceiling andch_idfromrz_mtu3_count_write()
* Replaced the error -EINVAL->-EBUSY forrz_mtu3_is_counter_invalid()
* Avoided race between rz_mtu3_count_{read, write} withrz_mtu3_cascade_counts_enable_set()by adding locks and moved the lock beforerz_mtu3_is_counter_invalid()
* Protected therz_mtu3_count_ceiling_read()function with a lock to make sure the cascade operation mode doesn't not change and that the priv data structure accesses don't race when they are changed in theceiling_write()callback.
* Added lock inrz_mtu3_cascade_enable_set()to make sure the other callbacks don't try to read the LWA state while updating LWA.
* Added lock inrz_mtu3_ext_input_phase_clock_select_set()to ensure the other callbacks don't try to read the PHCKSEL state while updating PHCKSEL.
* Added lock to avoid race betweenrz_mtu3_count_function_write()andrz_mtu3_action_read()
* Updatedrz_mtu3_action_readto return 0, if Synapse is inCOUNTER_SYNAPSE_ACTION_NONEstate.
* Replaced sysfs variablecascade_enable->cascade_counts_enable
* Renamedrz_mtu3_cascade_enable_get->rz_mtu3_cascade_counts_enable_get
* Renamedrz_mtu3_cascade_enable_set->rz_mtu3_cascade_counts_enable_set
* Removed redundent ceiling assignment fromrz_mtu3_count_ceiling_read()
* Removed unused ceiling andch_idfromrz_mtu3_count_write().v6->v7:
* Updated commit description
* Added Register descriptions
* Opimized size of cache variable by using union
* Usedtest_bit()inrz_mtu3_is_counter_invalid()
* Replacedval->timer_modein rz_mtu3_count_function_{read,write}
* Added TODO comment phase3 and phase5 modes.
* replaced if-else with ternary expression inrz_mtu3_count_direction_read()
* Used switch statement inrz_mtu3_count_ceiling_readto consistent with write
* Provided default case for all switch statement.
* Add mutex lock for avoiding races with other devices
* Updated comments inrz_mtu3_action_read
* ReplacedCOUNTER_COMP_DEVICE_BOOL->COUNTER_COMP_DEVICE_BOOLforcascade_enable
* ReplacedRZ_MTU3_GET_HW_CH->rz_mtu3_get_hw_ch
* Addedrz_mtu3_get_ch()to get channels
* usedrz_mtu3_shared_reg_update_bitforcascade_enableand selecting phase input clock.
* Addedrz_mtu3_is_counter_invalid()check inrz_mtu3_count_ceiling_read()v5->v6:
* Updated KConfig and commit description
* Sorted header
* FixedRZ_MTU3_GET_HW_CHMacro for argument reuse 'id' - possible side-effects?
* ReplacedSET_RUNTIME_PM_OPS->DEFINE_RUNTIME_DEV_PM_OPSand removed__maybe_unusedfrom suspend/resume()v4->v5:
* Updated theKconfigwith SoC vendor name
* Introducedrz_mtu3_is_counter_invalid()
* replaced pointer to an array of structrz_mtu3_channelwith
a simple pointer to structrz_mtu3_channel.
* Addedlong_word_access_ctrl_modesysfs entry for 16-bit and 32-bit access
* Addedexternal_input_phase_clock_selectsysfs entry for selecting input clocks.
* used preprocessor defines represent SIGNAL_{A,B,C,D}_ID instead of signal ids.v3->v4:
* There is no resource associated with "rz-mtu3-counter" compatible and moved the code to mfd subsystem as it binds against "rz-mtu".
* Removed structplatform_driverrz_mtu3_cnt_driver.
* Updated commit description
* UpdatedKconfigdescription
* Added macros RZ_MTU3_16_BIT_MTU{1,2}_CH for MTU1 and MTU2 channels
* AddedRZ_MTU3_GET_HW_CHmacro for getting channel ID.
* replaced priv->ch[id]->priv->ch[0] inrz_mtu3_count_read()
* Cached counter max values
* replacedcnt->tsrinrz_mtu3_count_direction_read()
* Added comments forRZ_MTU3_TCR_CCLR_NONE
* Replaced if with switch inrz_mtu3_initialize_counter()andrz_mtu3_count_ceiling_write()
* Added locks in initialize, terminate andenable_readto prevent races.
* Updatedrz_mtu3_action_readto take care of MTU2 signals.
* Added separate distinct array for each group of Synapse.
* Moved pm handling to parent.
v1->v3:
* Modelled as a counter device supporting 3 counters(2 16-bit and 32-bit)
* Add kernel-doc comments to document structrz_mtu3_cnt
* Removed mmio variable from structrz_mtu3_cnt
* Removed cnt local variable fromrz_mtu3_count_read()
* Replaced -EINVAL->-ERANGE for out of range error conditions.
* Removed explicit cast from write functions.
* Removed local variable val fromrz_mtu3_count_ceiling_read()
* Added lock for RMW for counter/ceiling updates.
* Added different synapses for counter0 and counter{1,2}
* Used ARRAY for assigningnum_counts.
* Added PM runtime for managing clocks.
* AddMODULE_IMPORT_NS(COUNTER)to import the COUNTER namespace.
Quoted 6 lines
--- drivers/counter/Kconfig | 11 + drivers/counter/Makefile | 1 + drivers/counter/rz-mtu3-cnt.c | 902 ++++++++++++++++++++++++++++++++++ 3 files changed, 914 insertions(+) create mode 100644 drivers/counter/rz-mtu3-cnt.c
Applied, thanks
--
Lee Jones [李琼斯]
Biju Das
maintainerPATCH v15 5/6 MAINTAINERS: Add entries for Renesas RZ/G2L MTU3a counter driver
In reply to Biju DasAdd the MAINTAINERS entries for the Renesas RZ/G2L MTU3a counter driver.
---v14->v15:
* No change.v13->v14:
* No change.v12->v13:
* No change.v11->v12:
* No change.
--- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+)
MAINTAINERS +8 -0
@@ -17924,6 +17924,14 @@ S: Supported F: Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml F: drivers/iio/adc/rzg2l_adc.c +RENESAS RZ/G2L MTU3a COUNTER DRIVER +M: Biju Das <[email protected]> +L: [email protected] +L: [email protected] +S: Supported +F: Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml +F: drivers/counter/rz-mtu3-cnt.c + RENESAS RZ/N1 A5PSW SWITCH DRIVER M: Clément Léger <[email protected]> L: [email protected]
Signature · 1 line
2.25.1
Re: [PATCH v15 5/6] MAINTAINERS: Add entries for Renesas RZ/G2L MTU3a counter driver
Quoted 13 lines · Biju Das
Add the
MAINTAINERSentries for the Renesas RZ/G2L MTU3a counter driver.Signed-off-by Biju Das <[email protected]>---
v14->v15:
* No change.v13->v14:
* No change.v12->v13:
* No change.v11->v12:
* No change.
Quoted 3 lines
--- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+)
Applied, thanks
--
Lee Jones [李琼斯]
Biju Das
maintainerPATCH v15 6/6 pwm: Add Renesas RZ/G2L MTU3a PWM driver
In reply to Biju DasThe RZ/G2L Multi-Function Timer Pulse Unit 3 (a.k.a MTU3a) uses one counter and two match components to configure duty_cycle and period to generate PWM output waveform.
Add basic support for RZ/G2L MTU3a PWM driver by creating separate PWM channels for each IOs.
---v14->v15:
* Updated copyright header and Limitations section
* Moved register definitions to <linux/mfd/rz-mtu3.h>
* Introduced new mapping table struct rz_mtu3_channel_io_map to hold the index of the lowest PWM and the number of PWMs handled by the HW channel.
* Introduced struct rz_mtu3_pwm_channel to hold mtu3 channel data and mapping table.
* Replaced rz_mtu3_get_hw_channel->rz_mtu3_get_channel and channel->hwpwm. The rz_mtu3_get_channel() returns struct rz_mtu3_pwm_channel*
* Dropped rz_mtu3_pwm_is_second_channel() as same can be obtained directly with new mapping (ie, priv->map->channel == pwm->hwpwm)
* Replaced ch_index->ch throughout and used "priv - rz_mtu3_pwm->channel_data" to find ch and dropped rz_mtu3_get_hw_channel_index().
* Optimized rz_mtu3_pwm_is_ch_enabled() by exit early, if is_channel_en is false.
* Updated rz_mtu3_pwm_request() and added comments.
* Introduced a bug in the driver by introducing enable_count, which increment/ decrement during enable()/disable().
* Reduced variable scope in rz_mtu3_pwm_get_state() by moving most of variables inside the if statement.
* Updated probe() to assign the struct rz_mtu3_pwm_channel values.v13->v14:
* Updated commit description
* Updated Limitations section.
* Replaced the macros RZ_MTU*->RZ_MTU3_CHAN_* in probe()
* Fixed a kernel crash in error path by moving rz_mtu3_pwm->chip.dev before devm_add_action_or_reset()
* Added pm_runtime_idle() and simplified error paths for devm_add_action_or_reset() and devm_pwmchip_add().v12->v13:
* Updated commit description
* Moved RZ_MTU3_TMDR1_MD_* macros to rz_mtu3.h
* Updated Limitations section.
* Removed PWM mode1 references from the driver.
* Dropped prescale and duty_cycle from struct rz_mtu3_pwm_chip.
* Replaced rz_mtu3_pwm_mode1_num_ios->rz_mtu3_hw_channel_ios.
* Avoided race condition in rz_mtu3_pwm_request()/rz_mtu3_pwm_free().
* Updated get_state() by adding dc > pv check and added a comment about overflow condition.
* Moved overflow condition check from config->probe()
* Replaced pm_runtime_resume_and_get with unconditional pm_runtime_get_sync() in config()
* Added error check for clk_prepare_enable() in probe() and propagating error to the caller for pm_runtime_resume()
* clk_get_rate() is called after enabling the clock and clk_rate_exclusive_put()v11->v12:
* Updated header file to <linux/mfd/rz-mtu3.h> as core driver is in MFD.
* Reordered get_state()v10->v11:
* No change.v9->v10:
* No change.v8->v9:
* Added prescale/duty_cycle variables to struct rz_mtu3_pwm_chip and cached this values in rz_mtu3_pwm_config and used this cached values in get_state(), if PWM is disabled.
* Added return code for get_state()v7->v8:
* Simplified rz_mtu3_pwm_request by calling rz_mtu3_request_channel()
* Simplified rz_mtu3_pwm_free by calling rz_mtu3_release_channel()v6->v7:
* Added channel specific mutex lock to avoid race between counter device and rz_mtu3_pwm_{request,free}
* Added pm_runtime_resume_and_get in rz_mtu3_pwm_enable()
* Added pm_runtime_put_sync in rz_mtu3_pwm_disable()
* Updated rz_mtu3_pwm_config()
* Updated rz_mtu3_pwm_apply()v5->v6:
* Updated commit and Kconfig description
* Sorted the header
* Replaced dev_get_drvdata from rz_mtu3_pwm_pm_disable()
* Replaced SET_RUNTIME_PM_OPS->DEFINE_RUNTIME_DEV_PM_OPS and removed __maybe_unused from suspend/resume()v4->v5:
* pwm device is instantiated by mtu3a core driver.v3->v4:
* There is no resource associated with "rz-mtu3-pwm" compatible
and moved the code to mfd subsystem as it binds against "rz-mtu".
* Removed struct platform_driver rz_mtu3_pwm_driver.v2->v3:
* No change.v1->v2:
* Modelled as a single PWM device handling multiple channles.
* Used PM framework to manage the clocks.
--- drivers/pwm/Kconfig | 11 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-rz-mtu3.c | 486 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 498 insertions(+) create mode 100644 drivers/pwm/pwm-rz-mtu3.c
drivers/pwm/Kconfig +11 -0
@@ -481,6 +481,17 @@ config PWM_ROCKCHIP Generic PWM framework driver for the PWM controller found on Rockchip SoCs. +config PWM_RZ_MTU3 + tristate "Renesas RZ/G2L MTU3a PWM Timer support" + depends on RZ_MTU3 || COMPILE_TEST + depends on HAS_IOMEM + help + This driver exposes the MTU3a PWM Timer controller found in Renesas + RZ/G2L like chips through the PWM API. + + To compile this driver as a module, choose M here: the module + will be called pwm-rz-mtu3. + config PWM_SAMSUNG tristate "Samsung PWM support" depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
drivers/pwm/Makefile +1 -0
@@ -44,6 +44,7 @@ obj-$(CONFIG_PWM_RASPBERRYPI_POE) += pwm-raspberrypi-poe.o obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o +obj-$(CONFIG_PWM_RZ_MTU3) += pwm-rz-mtu3.o obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o
drivers/pwm/pwm-rz-mtu3.c new file +486 -0
486 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [PATCH v15 6/6] pwm: Add Renesas RZ/G2L MTU3a PWM driver
Hello,
drivers/pwm/pwm-rz-mtu3.c line 114
Quoted 8 lines · Biju Das
drivers/pwm/pwm-rz-mtu3.c new file +8
-0+static struct rz_mtu3_pwm_channel * +rz_mtu3_get_channel (struct rz_mtu3_pwm_chip *rz_mtu3_pwm,u32 hwpwm) +{ +struct rz_mtu3_pwm_channel *priv = rz_mtu3_pwm->channel_data; +unsigned int ch; + +for (ch =0 ; ch <RZ_MTU3_MAX_HW_CHANNELS ; ch++, priv++) { +if (priv->map->channel + priv->map->num_channel_ios > hwpwm)
s/ / /
Quoted 14 lines
drivers/pwm/pwm-rz-mtu3.c new file +14
-0+break ; + } + +return priv; +} + +static bool rz_mtu3_pwm_is_ch_enabled (struct rz_mtu3_pwm_chip *rz_mtu3_pwm, +u32 hwpwm) +{ +struct rz_mtu3_pwm_channel *priv; +bool is_channel_en; +u8 val; + + priv =rz_mtu3_get_channel (rz_mtu3_pwm, hwpwm);
drivers/pwm/pwm-rz-mtu3.c line 138
Quoted 10 lines
drivers/pwm/pwm-rz-mtu3.c new file +10
-0+ is_channel_en =rz_mtu3_is_enabled (priv->mtu); +if (!is_channel_en) +return false; + +if (priv->map->channel == hwpwm) + val =rz_mtu3_8bit_ch_read (priv->mtu,RZ_MTU3_TIORH ); +else + val =rz_mtu3_8bit_ch_read (priv->mtu,RZ_MTU3_TIORL ); + +return (is_channel_en && (val &RZ_MTU3_TIOR_IOA ));
Here you already know that is_channel_en == true, so it can be dropped here.
Quoted 11 lines
drivers/pwm/pwm-rz-mtu3.c new file +10
-0+} + +static int rz_mtu3_pwm_enable (struct rz_mtu3_pwm_chip *rz_mtu3_pwm, +struct pwm_device *pwm) +{ +struct rz_mtu3_pwm_channel *priv; +u32 ch; +u8 val; +int rc; +
drivers/pwm/pwm-rz-mtu3.c line 205
Quoted 10 lines
drivers/pwm/pwm-rz-mtu3.c new file +10
-0+ rc =pm_runtime_resume_and_get (rz_mtu3_pwm->chip.dev); +if (rc) +return rc; + + priv =rz_mtu3_get_channel (rz_mtu3_pwm, pwm->hwpwm); + ch = priv - rz_mtu3_pwm->channel_data; + val =RZ_MTU3_TIOR_OC_IOB_TOGGLE |RZ_MTU3_TIOR_OC_IOA_H_COMP_MATCH ; + +rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TMDR1 ,RZ_MTU3_TMDR1_MD_PWMMODE1 ); +if (priv->map->channel == pwm->hwpwm)
This condition identifies the first PWM of a channel. I was surprised here that the channel numbering has a hole after each channel that manages two IOs. OTOH, in the comment at the top of the driver there is:
(The channels are MTU{0..4, 6, 7}.)which I would have expected to see in channel_map. I think the first member of this struct is really the base pwm number and so is misnamed?
Quoted 16 lines
drivers/pwm/pwm-rz-mtu3.c new file +16
-0+rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TIORH , val); + else + rz_mtu3_8bit_ch_write(priv->mtu, RZ_MTU3_TIORL, val); + +mutex_lock (&rz_mtu3_pwm->lock); +if (!rz_mtu3_pwm->enable_count[ch]) +rz_mtu3_enable (priv->mtu); + + rz_mtu3_pwm->enable_count[ch]++; +mutex_unlock (&rz_mtu3_pwm->lock); + +return 0 ; +} + +static void rz_mtu3_pwm_disable (struct rz_mtu3_pwm_chip *rz_mtu3_pwm, +struct pwm_device *pwm)
drivers/pwm/pwm-rz-mtu3.c line 231
Quoted 10 lines
drivers/pwm/pwm-rz-mtu3.c new file +10
-0+{ +struct rz_mtu3_pwm_channel *priv; +u32 ch; + + priv =rz_mtu3_get_channel (rz_mtu3_pwm, pwm->hwpwm); + ch = priv - rz_mtu3_pwm->channel_data; + +/* Return to normal mode and disable output pins of MTU3 channel */ +if (rz_mtu3_pwm->user_count[ch] <=1 ) +rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TMDR1 ,RZ_MTU3_TMDR1_MD_NORMAL );
This never triggers if both PWMs of a channel are requested, even if both are disabled. Is this intended?
Quoted 45 lines
drivers/pwm/pwm-rz-mtu3.c new file +44
-0+if (priv->map->channel == pwm->hwpwm) +rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TIORH ,RZ_MTU3_TIOR_OC_RETAIN ); +else +rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TIORL ,RZ_MTU3_TIOR_OC_RETAIN ); + +mutex_lock (&rz_mtu3_pwm->lock); + rz_mtu3_pwm->enable_count[ch]--; +if (!rz_mtu3_pwm->enable_count[ch]) +rz_mtu3_disable (priv->mtu); + +mutex_unlock (&rz_mtu3_pwm->lock); + +pm_runtime_put_sync (rz_mtu3_pwm->chip.dev); +} + +static int rz_mtu3_pwm_config (struct pwm_chip *chip,struct pwm_device *pwm, +const struct pwm_state *state) +{ +struct rz_mtu3_pwm_chip *rz_mtu3_pwm =to_rz_mtu3_pwm_chip (chip); +struct rz_mtu3_pwm_channel *priv; +unsigned long pv, dc; +u64 period_cycles; +u64 duty_cycles; +u8 prescale; +u8 val; + + priv =rz_mtu3_get_channel (rz_mtu3_pwm, pwm->hwpwm); + period_cycles =mul_u64_u32_div (state->period, rz_mtu3_pwm->rate, +NSEC_PER_SEC ); + prescale =rz_mtu3_pwm_calculate_prescale (rz_mtu3_pwm, period_cycles); + +if (period_cycles >> (2 * prescale) <=U16_MAX ) + pv = period_cycles >> (2 * prescale); +else + pv =U16_MAX ; + + duty_cycles =mul_u64_u32_div (state->duty_cycle, rz_mtu3_pwm->rate, +NSEC_PER_SEC ); +if (duty_cycles >> (2 * prescale) <=U16_MAX ) + dc = duty_cycles >> (2 * prescale); +else + dc =U16_MAX ; + +/*
drivers/pwm/pwm-rz-mtu3.c line 327
Quoted 10 lines
drivers/pwm/pwm-rz-mtu3.c new file +10
-0+* If the PWM channel is disabled, make sure to turn on the clock +* before writing the register. +*/ +if (!pwm->state.enabled) +pm_runtime_get_sync (chip->dev); + + val =RZ_MTU3_TCR_CKEG_RISING | prescale; +if (priv->map->channel == pwm->hwpwm) { +rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TCR , +RZ_MTU3_TCR_CCLR_TGRA | val);
If the sibling PWM on the same channel is on, you're overwriting its prescale value here, are you not?
Quoted 10 lines
drivers/pwm/pwm-rz-mtu3.c new file +10
-0+rz_mtu3_16bit_ch_write (priv->mtu,RZ_MTU3_TGRB , dc); +rz_mtu3_16bit_ch_write (priv->mtu,RZ_MTU3_TGRA , pv); + }else { +rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TCR , +RZ_MTU3_TCR_CCLR_TGRC | val); +rz_mtu3_16bit_ch_write (priv->mtu,RZ_MTU3_TGRD , dc); +rz_mtu3_16bit_ch_write (priv->mtu,RZ_MTU3_TGRC , pv); + } + +/* If the PWM is not enabled, turn the clock off again to save power. */
drivers/pwm/pwm-rz-mtu3.c line 410
Quoted 10 lines
drivers/pwm/pwm-rz-mtu3.c new file +9
-0+if (!pwm->state.enabled) +pm_runtime_put (chip->dev); + +return 0 ; +} + +static int rz_mtu3_pwm_probe (struct platform_device *pdev) +{ +struct rz_mtu3 *ddata =dev_get_drvdata (pdev->dev.parent);
Nitpick: I would have called that parent_ddata.
Quoted 11 lines
drivers/pwm/pwm-rz-mtu3.c new file +11
-0+struct rz_mtu3_pwm_chip *rz_mtu3_pwm; +struct device *dev = &pdev->dev; +unsigned int i, j =0 ; +int ret; + + rz_mtu3_pwm =devm_kzalloc (&pdev->dev,sizeof (*rz_mtu3_pwm),GFP_KERNEL ); +if (!rz_mtu3_pwm) +return -ENOMEM ; + + rz_mtu3_pwm->clk = ddata->clk; +
drivers/pwm/pwm-rz-mtu3.c line 431
Quoted 10 lines
drivers/pwm/pwm-rz-mtu3.c new file +10
-0+for (i =0 ; i <RZ_MTU_NUM_CHANNELS ; i++) { +if (i ==RZ_MTU3_CHAN_5 || i ==RZ_MTU3_CHAN_8 ) +continue ; + + rz_mtu3_pwm->channel_data[j].mtu = &ddata->channels[i]; + rz_mtu3_pwm->channel_data[j].mtu->dev = dev; + rz_mtu3_pwm->channel_data[j].map = &channel_map[j]; + j++; + } +
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-König | Industrial Linux Solutions | https://www.pengutronix.de/ |
Biju Das
maintainerRE: [PATCH v15 6/6] pwm: Add Renesas RZ/G2L MTU3a PWM driver
Hi Uwe,
Thanks for the feedback.
Quoted 5 lines
Subject: Re: [PATCH v15 6/6] pwm: Add Renesas RZ/G2L MTU3a PWM driver
Hello,
On Thu, Mar 30, 2023 at 12:16:32PM +0100, Biju Das wrote:
Quoted 10 lines
drivers/pwm/pwm-rz-mtu3.c line 114
Quoted 8 lines
drivers/pwm/pwm-rz-mtu3.c new file +8
-0+static struct rz_mtu3_pwm_channel * +rz_mtu3_get_channel (struct rz_mtu3_pwm_chip *rz_mtu3_pwm,u32 hwpwm) +{ +struct rz_mtu3_pwm_channel *priv = rz_mtu3_pwm->channel_data; +unsigned int ch; + +for (ch =0 ; ch <RZ_MTU3_MAX_HW_CHANNELS ; ch++, priv++) { +if (priv->map->channel + priv->map->num_channel_ios > hwpwm)s/ / /
OK, will fix this.
Quoted 20 lines
drivers/pwm/pwm-rz-mtu3.c
Quoted 8 lines
drivers/pwm/pwm-rz-mtu3.c new file +7
-0+break ; + } + +return priv; +} + +static bool rz_mtu3_pwm_is_ch_enabled(struct rz_mtu3_pwm_chip
*rz_mtu3_pwm,Quoted 11 lines
drivers/pwm/pwm-rz-mtu3.c new file +11
-0+ u32 hwpwm) +{ +struct rz_mtu3_pwm_channel *priv; +bool is_channel_en; +u8 val; + + priv =rz_mtu3_get_channel (rz_mtu3_pwm, hwpwm); + is_channel_en =rz_mtu3_is_enabled (priv->mtu); +if (!is_channel_en) +return false; +
Quoted 8 lines
drivers/pwm/pwm-rz-mtu3.c line 138
Quoted 6 lines
drivers/pwm/pwm-rz-mtu3.c new file +6
-0+if (priv->map->channel == hwpwm) + val =rz_mtu3_8bit_ch_read (priv->mtu,RZ_MTU3_TIORH ); +else + val =rz_mtu3_8bit_ch_read (priv->mtu,RZ_MTU3_TIORL ); + +return (is_channel_en && (val &RZ_MTU3_TIOR_IOA ));Here you already know that
is_channel_en== true, so it can be dropped here.
Agreed.
Quoted 28 lines
Quoted 11 lines
drivers/pwm/pwm-rz-mtu3.c new file +9
-0+} + +static int rz_mtu3_pwm_enable (struct rz_mtu3_pwm_chip *rz_mtu3_pwm, +struct pwm_device *pwm) +{ +struct rz_mtu3_pwm_channel *priv; +u32 ch; +u8 val; +int rc;drivers/pwm/pwm-rz-mtu3.c
Quoted 10 lines
drivers/pwm/pwm-rz-mtu3.c new file +10
-0+ + rc =pm_runtime_resume_and_get (rz_mtu3_pwm->chip.dev); +if (rc) +return rc; + + priv =rz_mtu3_get_channel (rz_mtu3_pwm, pwm->hwpwm); + ch = priv - rz_mtu3_pwm->channel_data; + val =RZ_MTU3_TIOR_OC_IOB_TOGGLE |RZ_MTU3_TIOR_OC_IOA_H_COMP_MATCH ; + + rz_mtu3_8bit_ch_write(priv->mtu, RZ_MTU3_TMDR1,
RZ_MTU3_TMDR1_MD_PWMMODE1);Review
Quoted 1 line
(quoted diff) +1
-0+ if (priv->map->channel == pwm->hwpwm)This condition identifies the first PWM of a channel. I was surprised here that the channel numbering has a hole after each channel that manages two IOs. OTOH, in the comment at the top of the driver there is:
Quoted 4 lines
(The channels are MTU{0..4, 6, 7}.)which I would have expected to see in
channel_map. I think the first member of this struct is really the base pwm number and so is misnamed?
Ok will change the variable to base_pwm_number.
* @base_pwm_number: First PWM of a channel
and add the below comment in channel_map.
+/*
+ * The MTU channels are {0..4, 6, 7} and The number of IO on MTU1
+ * and MTU2 channel is 1 compared to 2 on others.
+ */
Quoted 23 lines
Quoted 23 lines
drivers/pwm/pwm-rz-mtu3.c new file +22
-0+rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TIORH , val); + else + rz_mtu3_8bit_ch_write(priv->mtu, RZ_MTU3_TIORL, val); + +mutex_lock (&rz_mtu3_pwm->lock); +if (!rz_mtu3_pwm->enable_count[ch]) +rz_mtu3_enable (priv->mtu); + + rz_mtu3_pwm->enable_count[ch]++; +mutex_unlock (&rz_mtu3_pwm->lock); + +return 0 ; +} + +static void rz_mtu3_pwm_disable (struct rz_mtu3_pwm_chip *rz_mtu3_pwm, +struct pwm_device *pwm) +{ +struct rz_mtu3_pwm_channel *priv; +u32 ch; + + priv =rz_mtu3_get_channel (rz_mtu3_pwm, pwm->hwpwm); + ch = priv - rz_mtu3_pwm->channel_data;
Quoted 8 lines
drivers/pwm/pwm-rz-mtu3.c
Quoted 5 lines
drivers/pwm/pwm-rz-mtu3.c new file +5
-0+ +/* Return to normal mode and disable output pins of MTU3 channel */ +if (rz_mtu3_pwm->user_count[ch] <=1 ) +rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TMDR1 , +RZ_MTU3_TMDR1_MD_NORMAL );This never triggers if both PWMs of a channel are requested, even if both are disabled. Is this intended?
It is not required. Will take out this.
Quoted 54 lines
Review
Quoted 3 lines
(quoted diff) +2
-0+ if (priv->map->channel == pwm->hwpwm) + rz_mtu3_8bit_ch_write(priv->mtu, RZ_MTU3_TIORH,
RZ_MTU3_TIOR_OC_RETAIN);Quoted 6 lines
drivers/pwm/pwm-rz-mtu3.c new file +6
-0+else +rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TIORL , +RZ_MTU3_TIOR_OC_RETAIN ); + +mutex_lock (&rz_mtu3_pwm->lock); + rz_mtu3_pwm->enable_count[ch]--;drivers/pwm/pwm-rz-mtu3.c
Quoted 10 lines
drivers/pwm/pwm-rz-mtu3.c new file +9
-0+if (!rz_mtu3_pwm->enable_count[ch]) +rz_mtu3_disable (priv->mtu); + +mutex_unlock (&rz_mtu3_pwm->lock); + +pm_runtime_put_sync (rz_mtu3_pwm->chip.dev); +} + +static int rz_mtu3_pwm_config(struct pwm_chip *chip, struct pwm_device*pwm,
Quoted 33 lines
drivers/pwm/pwm-rz-mtu3.c new file +33
-0+ const struct pwm_state *state) { +struct rz_mtu3_pwm_chip *rz_mtu3_pwm =to_rz_mtu3_pwm_chip (chip); +struct rz_mtu3_pwm_channel *priv; +unsigned long pv, dc; +u64 period_cycles; +u64 duty_cycles; +u8 prescale; +u8 val; + + priv =rz_mtu3_get_channel (rz_mtu3_pwm, pwm->hwpwm); + period_cycles =mul_u64_u32_div (state->period, rz_mtu3_pwm->rate, +NSEC_PER_SEC ); + prescale =rz_mtu3_pwm_calculate_prescale (rz_mtu3_pwm, +period_cycles); + +if (period_cycles >> (2 * prescale) <=U16_MAX ) + pv = period_cycles >> (2 * prescale); +else + pv =U16_MAX ; + + duty_cycles =mul_u64_u32_div (state->duty_cycle, rz_mtu3_pwm->rate, +NSEC_PER_SEC ); +if (duty_cycles >> (2 * prescale) <=U16_MAX ) + dc = duty_cycles >> (2 * prescale); +else + dc =U16_MAX ; + +/* +* If the PWM channel is disabled, make sure to turn on the clock +* before writing the register. +*/ +if (!pwm->state.enabled) +pm_runtime_get_sync (chip->dev);
Quoted 8 lines
drivers/pwm/pwm-rz-mtu3.c line 327
Quoted 5 lines
drivers/pwm/pwm-rz-mtu3.c new file +5
-0+ + val =RZ_MTU3_TCR_CKEG_RISING | prescale; +if (priv->map->channel == pwm->hwpwm) { +rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TCR , +RZ_MTU3_TCR_CCLR_TGRA | val);If the sibling PWM on the same channel is on, you're overwriting its prescale value here, are you not?
Yes, you are correct. Will cache prescale and add the below code in rz_mtu3_pwm_config(). Is it ok?
+ * Prescalar is shared by multiple channels, so prescale can + * NOT be modified when there are multiple channels in use with + * different settings. + */
+ if (prescale != rz_mtu3_pwm->prescale[ch] && rz_mtu3_pwm->user_count[ch] > 1)
+ return -EBUSY;
+
+ /*
+ * Prescalar is shared by multiple channels, we cache the prescalar value + * from the first enabled channel and use the same value for both + * channels. + */
+ rz_mtu3_pwm->prescale[ch] = prescale;
+
Quoted 12 lines
drivers/pwm/pwm-rz-mtu3.c
Quoted 11 lines
drivers/pwm/pwm-rz-mtu3.c new file +10
-0+rz_mtu3_16bit_ch_write (priv->mtu,RZ_MTU3_TGRB , dc); +rz_mtu3_16bit_ch_write (priv->mtu,RZ_MTU3_TGRA , pv); + }else { +rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TCR , +RZ_MTU3_TCR_CCLR_TGRC | val); +rz_mtu3_16bit_ch_write (priv->mtu,RZ_MTU3_TGRD , dc); +rz_mtu3_16bit_ch_write (priv->mtu,RZ_MTU3_TGRC , pv); + } + +/* If the PWM is not enabled, turn the clock off again to save power. */
Quoted 11 lines
drivers/pwm/pwm-rz-mtu3.c line 410
Quoted 9 lines
drivers/pwm/pwm-rz-mtu3.c new file +8
-0+if (!pwm->state.enabled) +pm_runtime_put (chip->dev); + +return 0 ; +} + +static int rz_mtu3_pwm_probe (struct platform_device *pdev) { +struct rz_mtu3 *ddata =dev_get_drvdata (pdev->dev.parent);Nitpick: I would have called that
parent_ddata.
Agreed.
Cheers,
Biju
Quoted 30 lines
drivers/pwm/pwm-rz-mtu3.c
Quoted 7 lines
drivers/pwm/pwm-rz-mtu3.c new file +6
-0+struct rz_mtu3_pwm_chip *rz_mtu3_pwm; +struct device *dev = &pdev->dev; +unsigned int i, j =0 ; +int ret; + + rz_mtu3_pwm = devm_kzalloc(&pdev->dev, sizeof(*rz_mtu3_pwm),
GFP_KERNEL);Quoted 5 lines
drivers/pwm/pwm-rz-mtu3.c new file +5
-0+if (!rz_mtu3_pwm) +return -ENOMEM ; + + rz_mtu3_pwm->clk = ddata->clk; +drivers/pwm/pwm-rz-mtu3.c line 431
Quoted 10 lines
drivers/pwm/pwm-rz-mtu3.c new file +10
-0+for (i =0 ; i <RZ_MTU_NUM_CHANNELS ; i++) { +if (i ==RZ_MTU3_CHAN_5 || i ==RZ_MTU3_CHAN_8 ) +continue ; + + rz_mtu3_pwm->channel_data[j].mtu = &ddata->channels[i]; + rz_mtu3_pwm->channel_data[j].mtu->dev = dev; + rz_mtu3_pwm->channel_data[j].map = &channel_map[j]; + j++; + } +Best regards
Uwe--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | https://www.pengutronix.de/ |
Re: [PATCH v15 6/6] pwm: Add Renesas RZ/G2L MTU3a PWM driver
Hello,
Quoted 12 lines · Biju Das
Quoted 8 lines · Biju Das
drivers/pwm/pwm-rz-mtu3.c line 327
Quoted 4 lines
drivers/pwm/pwm-rz-mtu3.c new file +4
-0+ val =RZ_MTU3_TCR_CKEG_RISING | prescale; +if (priv->map->channel == pwm->hwpwm) { +rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TCR , +RZ_MTU3_TCR_CCLR_TGRA | val);If the sibling PWM on the same channel is on, you're overwriting its prescale value here, are you not?
Yes, you are correct. Will cache prescale and add the below code in
rz_mtu3_pwm_config(). Is it ok?
Review
Quoted 6 lines
(quoted diff) +6
-0+ * Prescalar is shared by multiple channels, so prescale can + * NOT be modified when there are multiple channels in use with + * different settings. + */ + if (prescale != rz_mtu3_pwm->prescale[ch] && rz_mtu3_pwm->user_count[ch] > 1) + return -EBUSY;
If the other PWM is off, you can (and should) change the prescale value. Also if the current prescale value is less than the one you want to set, you can handle that.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-König | Industrial Linux Solutions | https://www.pengutronix.de/ |
Biju Das
maintainerRE: [PATCH v15 6/6] pwm: Add Renesas RZ/G2L MTU3a PWM driver
Hi Uwe,
Thanks for the feedback.
Quoted 25 lines
Subject: Re: [PATCH v15 6/6] pwm: Add Renesas RZ/G2L MTU3a PWM driver
Hello,
Quoted 17 lines · Biju Das
Quoted 8 lines · Biju Das
drivers/pwm/pwm-rz-mtu3.c line 327
Quoted 4 lines
drivers/pwm/pwm-rz-mtu3.c new file +4
-0+ val =RZ_MTU3_TCR_CKEG_RISING | prescale; +if (priv->map->channel == pwm->hwpwm) { +rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TCR , +RZ_MTU3_TCR_CCLR_TGRA | val);If the sibling PWM on the same channel is on, you're overwriting its prescale value here, are you not?
Yes, you are correct. Will cache prescale and add the below code in
rz_mtu3_pwm_config(). Is it ok?(quoted diff) +5
-0+ * Prescalar is shared by multiple channels, so prescale can + * NOT be modified when there are multiple channels in use with + * different settings. + */ + if (prescale != rz_mtu3_pwm->prescale[ch] && rz_mtu3_pwm-Quoted 2 lines
user_count[ch] > 1)
+ return-EBUSY;
Quoted 4 lines
If the other PWM is off, you can (and should) change the prescale value. Also if the current prescale value is less than the one you want to set, you can handle that.
You mean like below??
static int rz_mtu3_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state)
{
struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
struct rz_mtu3_pwm_channel *priv;
u64 period_cycles;
u64 duty_cycles;
u8 prescale;
u16 pv, dc;
u8 val;
u32 ch;
priv = rz_mtu3_get_channel(rz_mtu3_pwm, pwm->hwpwm);
ch = priv - rz_mtu3_pwm->channel_data;
period_cycles = mul_u64_u32_div(state->period, rz_mtu3_pwm->rate,
NSEC_PER_SEC);
prescale = rz_mtu3_pwm_calculate_prescale(rz_mtu3_pwm, period_cycles);
/*
* Prescalar is shared by multiple channels, so prescale can
* NOT be modified when there are multiple channels in use with
* different settings. Modify prescalar if other PWM is off or current
* prescale value is less than the one we want to set.
*/
if (rz_mtu3_pwm->enable_count[ch] > 1 &&
rz_mtu3_pwm->prescale[ch] > prescale)
return -EBUSY;
pv = rz_mtu3_pwm_calculate_pv_or_dc(period_cycles, prescale);
duty_cycles = mul_u64_u32_div(state->duty_cycle, rz_mtu3_pwm->rate,
NSEC_PER_SEC);
dc = rz_mtu3_pwm_calculate_pv_or_dc(duty_cycles, prescale);
/*
* If the PWM channel is disabled, make sure to turn on the clock
* before writing the register.
*/
if (!pwm->state.enabled)
pm_runtime_get_sync(chip->dev);
val = RZ_MTU3_TCR_CKEG_RISING | prescale;
/* Counter must be stopped while updating TCR register */
if (rz_mtu3_pwm->prescale[ch] != prescale && rz_mtu3_pwm->enable_count[ch])
rz_mtu3_disable(priv->mtu);
if (priv->map->base_pwm_number == pwm->hwpwm) {
rz_mtu3_8bit_ch_write(priv->mtu, RZ_MTU3_TCR,
RZ_MTU3_TCR_CCLR_TGRA | val);
rz_mtu3_pwm_write_tgr_registers(priv, RZ_MTU3_TGRA, pv,
RZ_MTU3_TGRB, dc);
/* Update pv and dc of other PWM based on new prescalar */
if (rz_mtu3_pwm->prescale[ch] != prescale &&
rz_mtu3_pwm->enable_count[ch] > 1) {
rz_mtu3_pwm_read_tgr_registers(priv, RZ_MTU3_TGRC, &pv,
RZ_MTU3_TGRD, &dc);
rz_mtu3_pwm_calculate_new_pv_dc(rz_mtu3_pwm->rate, &pv,
&dc, prescale);
rz_mtu3_pwm_write_tgr_registers(priv, RZ_MTU3_TGRC,
pv, RZ_MTU3_TGRD, dc);
}
} else {
rz_mtu3_8bit_ch_write(priv->mtu, RZ_MTU3_TCR,
RZ_MTU3_TCR_CCLR_TGRC | val);
rz_mtu3_pwm_write_tgr_registers(priv, RZ_MTU3_TGRC, pv,
RZ_MTU3_TGRD, dc);
/* Update pv and dc of other PWM based on new prescalar */
if (rz_mtu3_pwm->prescale[ch] != prescale &&
rz_mtu3_pwm->enable_count[ch] > 1) {
rz_mtu3_pwm_read_tgr_registers(priv, RZ_MTU3_TGRA, &pv,
RZ_MTU3_TGRB, &dc);
rz_mtu3_pwm_calculate_new_pv_dc(rz_mtu3_pwm->rate, &pv,
&dc, prescale);
rz_mtu3_pwm_write_tgr_registers(priv, RZ_MTU3_TGRA, pv,
RZ_MTU3_TGRB, dc);
}
}
if (rz_mtu3_pwm->prescale[ch] != prescale) {
/*
* Prescalar is shared by multiple channels, we cache the
* prescalar value and use the same value for both channels.
*/
rz_mtu3_pwm->prescale[ch] = prescale;
if (rz_mtu3_pwm->enable_count[ch])
rz_mtu3_enable(priv->mtu);
}
/* If the PWM is not enabled, turn the clock off again to save power. */
if (!pwm->state.enabled)
pm_runtime_put(chip->dev);
return 0;
}Helper functions:
static void rz_mtu3_pwm_read_tgr_registers(struct rz_mtu3_pwm_channel *priv,
u16 reg_pv_offset, u16 *pv_val,
u16 reg_dc_offset, u16 *dc_val)
{
*pv_val = rz_mtu3_16bit_ch_read(priv->mtu, reg_pv_offset);
*dc_val = rz_mtu3_16bit_ch_read(priv->mtu, reg_dc_offset);
}static void rz_mtu3_pwm_write_tgr_registers(struct rz_mtu3_pwm_channel *priv,
u16 reg_pv_offset, u16 pv_val,
u16 reg_dc_offset, u16 dc_val)
{
rz_mtu3_16bit_ch_write(priv->mtu, reg_pv_offset, pv_val);
rz_mtu3_16bit_ch_write(priv->mtu, reg_dc_offset, dc_val);
}static u64 rz_mtu3_pwm_get_period_or_duty_cycle(unsigned long pwm_rate,
u16 val, u8 prescale)
{
u64 tmp;
/* With prescale <= 7 and pv <= 0xffff this doesn't overflow. */
tmp = NSEC_PER_SEC * (u64)val << (2 * prescale);
return DIV_ROUND_UP_ULL(tmp, pwm_rate);
}static u16 rz_mtu3_pwm_calculate_pv_or_dc(u64 period_or_duty_cycle, u8 prescale)
{
return (period_or_duty_cycle >> (2 * prescale)) <= U16_MAX ?
period_or_duty_cycle >> (2 * prescale) : U16_MAX;
}static void rz_mtu3_pwm_calculate_new_pv_dc(unsigned long pwm_rate,
u16 *pv, u16 *dc, u8 prescale)
{
u64 tmp;
tmp = rz_mtu3_pwm_get_period_or_duty_cycle(pwm_rate, *pv, prescale);
tmp = mul_u64_u32_div(tmp, pwm_rate, NSEC_PER_SEC);
*pv = rz_mtu3_pwm_calculate_pv_or_dc(tmp, prescale);
tmp = rz_mtu3_pwm_get_period_or_duty_cycle(pwm_rate, *dc, prescale);
tmp = mul_u64_u32_div(tmp, pwm_rate, NSEC_PER_SEC);
*dc = rz_mtu3_pwm_calculate_pv_or_dc(tmp, prescale);
}And in apply, add lock around config()
mutex_lock(&rz_mtu3_pwm->lock); ret = rz_mtu3_pwm_config(chip, pwm, state); mutex_unlock(&rz_mtu3_pwm->lock);
Cheers,
Biju
Re: [PATCH v15 6/6] pwm: Add Renesas RZ/G2L MTU3a PWM driver
Hello Biju,
Quoted 56 lines · Biju Das
Thanks for the feedback.
Quoted 25 lines
Subject: Re: [PATCH v15 6/6] pwm: Add Renesas RZ/G2L MTU3a PWM driver
Hello,
Quoted 17 lines · Biju Das
Quoted 8 lines · Biju Das
drivers/pwm/pwm-rz-mtu3.c line 327
Quoted 4 lines
drivers/pwm/pwm-rz-mtu3.c new file +4
-0+ val =RZ_MTU3_TCR_CKEG_RISING | prescale; +if (priv->map->channel == pwm->hwpwm) { +rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TCR , +RZ_MTU3_TCR_CCLR_TGRA | val);If the sibling PWM on the same channel is on, you're overwriting its prescale value here, are you not?
Yes, you are correct. Will cache prescale and add the below code in
rz_mtu3_pwm_config(). Is it ok?(quoted diff) +5
-0+ * Prescalar is shared by multiple channels, so prescale can + * NOT be modified when there are multiple channels in use with + * different settings. + */ + if (prescale != rz_mtu3_pwm->prescale[ch] && rz_mtu3_pwm-Quoted 2 lines
user_count[ch] > 1)
+ return-EBUSY;Quoted 4 lines
If the other PWM is off, you can (and should) change the prescale value. Also if the current prescale value is less than the one you want to set, you can handle that.
You mean like below??
static int rz_mtu3_pwm_config(struct
pwm_chip*chip, structpwm_device*pwm,
const structpwm_state*state){ struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip); struct rz_mtu3_pwm_channel *priv; u64 period_cycles; u64 duty_cycles; u8 prescale; u16 pv, dc; u8 val; u32 ch; priv = rz_mtu3_get_channel(rz_mtu3_pwm, pwm->hwpwm); ch = priv - rz_mtu3_pwm->channel_data; period_cycles = mul_u64_u32_div(state->period, rz_mtu3_pwm->rate, NSEC_PER_SEC); prescale = rz_mtu3_pwm_calculate_prescale(rz_mtu3_pwm, period_cycles); /* * Prescalar is shared by multiple channels, so prescale can * NOT be modified when there are multiple channels in use with
Quoted 8 lines
* different settings. Modify prescalar if other PWM is off or current * prescale value is less than the one we want to set. */ if (rz_mtu3_pwm->enable_count[ch] > 1 && rz_mtu3_pwm->prescale[ch] > prescale) return -EBUSY; pv = rz_mtu3_pwm_calculate_pv_or_dc(period_cycles, prescale);
Here it starts to get wrong. If rz_mtu3_pwm->enable_count[ch] > 1 you have to use rz_mtu3_pwm->prescale[ch] instead of prescale.
Best regards
Uwe
Signature · 2 lines
Pengutronix e.K. | Uwe Kleine-König | Industrial Linux Solutions | https://www.pengutronix.de/ |
Biju Das
maintainerRE: [PATCH v15 6/6] pwm: Add Renesas RZ/G2L MTU3a PWM driver
Hi Uwe,
Quoted 81 lines
-----Original Message-----
From: Uwe Kleine-König <[email protected]>
Sent: Monday, April 17, 2023 11:42 PM
To: Biju Das <[email protected]>
Cc: [email protected]; Chris Paterson <[email protected]>; Lee Jones <[email protected]>; Geert Uytterhoeven <[email protected]>; William Breathitt Gray <[email protected]>; Daniel Lezcano <[email protected]>; Prabhakar Mahadev Lad <prabhakar.mahadev- [email protected]>; [email protected]; Thierry Reding <[email protected]>; [email protected]
Subject: Re: [PATCH v15 6/6] pwm: Add Renesas RZ/G2L MTU3a PWM driverHello Biju,
Quoted 22 lines · Biju Das
Thanks for the feedback.
Quoted 20 lines
Subject: Re: [PATCH v15 6/6] pwm: Add Renesas RZ/G2L MTU3a PWM driver
Hello,
Quoted 14 lines · Biju Das
Quoted 8 lines · Biju Das
drivers/pwm/pwm-rz-mtu3.c line 327
Quoted 4 lines
drivers/pwm/pwm-rz-mtu3.c new file +4
-0+ val =RZ_MTU3_TCR_CKEG_RISING | prescale; +if (priv->map->channel == pwm->hwpwm) { +rz_mtu3_8bit_ch_write (priv->mtu,RZ_MTU3_TCR , +RZ_MTU3_TCR_CCLR_TGRA | val);If the sibling PWM on the same channel is on, you're overwriting its prescale value here, are you not?
Yes, you are correct. Will cache prescale and add the below code in
rz_mtu3_pwm_config(). Is it ok?(quoted diff) +2
-0+ * Prescalar is shared by multiple channels, so prescale can + * NOT be modified when there are multiple channels in usewith
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
(quoted diff) +3
-0+ * different settings. + */ + if (prescale != rz_mtu3_pwm->prescale[ch] && rz_mtu3_pwm-user_count[ch] > 1)
+ return-EBUSY;Quoted 8 lines
Quoted 4 lines
If the other PWM is off, you can (and should) change the prescale value. Also if the current prescale value is less than the one you want to set, you can handle that.
You mean like below??
static int rz_mtu3_pwm_config(struct
pwm_chip*chip, structpwm_device*pwm,
Quoted 28 lines
const struct pwm_state *state) { struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip); struct rz_mtu3_pwm_channel *priv; u64 period_cycles; u64 duty_cycles; u8 prescale; u16 pv, dc; u8 val; u32 ch; priv = rz_mtu3_get_channel(rz_mtu3_pwm, pwm->hwpwm); ch = priv - rz_mtu3_pwm->channel_data; period_cycles = mul_u64_u32_div(state->period, rz_mtu3_pwm->rate, NSEC_PER_SEC); prescale = rz_mtu3_pwm_calculate_prescale(rz_mtu3_pwm,
period_cycles);/* * Prescalar is shared by multiple channels, so prescale can * NOT be modified when there are multiple channels in use with * different settings. Modify prescalar if other PWM is off or current * prescale value is less than the one we want to set. */ if (rz_mtu3_pwm->enable_count[ch] > 1 && rz_mtu3_pwm->prescale[ch] > prescale) return -EBUSY;
Quoted 4 lines
Quoted 1 line
pv = rz_mtu3_pwm_calculate_pv_or_dc(period_cycles, prescale);Here it starts to get wrong. If rz_mtu3_pwm->enable_count[ch] > 1 you have to use rz_mtu3_pwm->prescale[ch] instead of prescale.
Thanks for correcting me. Will test with these changes and send v16 for PWM alone as core driver patch is already in Linux-next[1]
Cheers,
Biju