From patchwork Mon Nov 20 11:33:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Biju Das X-Patchwork-Id: 1865945 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=linux-pwm-owner@vger.kernel.org; receiver=patchwork.ozlabs.org) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4SYlkc3tFkz1ySC for ; Mon, 20 Nov 2023 22:33:28 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233216AbjKTLdZ (ORCPT ); Mon, 20 Nov 2023 06:33:25 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53726 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232627AbjKTLdW (ORCPT ); Mon, 20 Nov 2023 06:33:22 -0500 Received: from relmlie5.idc.renesas.com (relmlor1.renesas.com [210.160.252.171]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id AB3D190; Mon, 20 Nov 2023 03:33:16 -0800 (PST) X-IronPort-AV: E=Sophos;i="6.04,213,1695654000"; d="scan'208";a="183596142" Received: from unknown (HELO relmlir5.idc.renesas.com) ([10.200.68.151]) by relmlie5.idc.renesas.com with ESMTP; 20 Nov 2023 20:33:16 +0900 Received: from localhost.localdomain (unknown [10.226.93.17]) by relmlir5.idc.renesas.com (Postfix) with ESMTP id 16F3F4048F35; Mon, 20 Nov 2023 20:33:10 +0900 (JST) From: Biju Das To: Thierry Reding , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel Cc: Biju Das , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, Geert Uytterhoeven , Chris Paterson , Biju Das , Fabrizio Castro , Prabhakar Mahadev Lad , linux-renesas-soc@vger.kernel.org Subject: [PATCH v17 0/4] Add support for RZ/G2L GPT Date: Mon, 20 Nov 2023 11:33:03 +0000 Message-Id: <20231120113307.80710-1-biju.das.jz@bp.renesas.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-Spam-Status: No, score=0.6 required=5.0 tests=AC_FROM_MANY_DOTS,BAYES_00, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-pwm@vger.kernel.org RZ/G2L General PWM Timer (GPT) composed of 8 channels with 32-bit timer (GPT32E). It supports the following functions * 32 bits × 8 channels * Up-counting or down-counting (saw waves) or up/down-counting (triangle waves) for each counter. * Clock sources independently selectable for each channel * Two I/O pins per channel * Two output compare/input capture registers per channel * For the two output compare/input capture registers of each channel, four registers are provided as buffer registers and are capable of operating as comparison registers when buffering is not in use. * In output compare operation, buffer switching can be at crests or troughs, enabling the generation of laterally asymmetric PWM waveforms. * Registers for setting up frame cycles in each channel (with capability for generating interrupts at overflow or underflow) * Generation of dead times in PWM operation * Synchronous starting, stopping and clearing counters for arbitrary channels * Starting, stopping, clearing and up/down counters in response to input level comparison * Starting, clearing, stopping and up/down counters in response to a maximum of four external triggers * Output pin disable function by dead time error and detected short-circuits between output pins * A/D converter start triggers can be generated (GPT32E0 to GPT32E3) * Enables the noise filter for input capture and external trigger operation This patch series aims to add basic pwm support for RZ/G2L GPT driver by creating separate logical channels for each IOs. v16->v17: * Added ret = dev_err_probe() to avoid return success in probe(). * Dropped unneeded MODULE_ALIAS(). * Dropped .owner from struct rzg2l_gpt_ops. * Fixed build issue reported by kernel test robot by replacing DIV_ROUND_UP()->DIV64_U64_ROUND_UP() in rzg2l_gpt_calculate_pv_or_dc(). * Added max_val to struct rzg2l_gpt_chip to compute maximum period supported by the HW in probe() and limit its value in apply() to avoid 64-bit overflow with computation. * Added helper function calculate_period_or_duty() to avoid losing precision for smaller period/duty cycle values ((2^32 * 10^9 << 2) < 2^64), by not processing the rounded values. * Replaced mul_u64_u64_div_u64()->mul_u64_u32_div() as the former is giving warnings with CONFIG_PWM_DEBUG enabled for very high values. eg: echo "###### Medium setting 11000 sec = 3hours ##" echo 11000000000000 > /sys/class/pwm/$PWMCHIP/pwm${IO_1}/period echo 5500000000000 > /sys/class/pwm/$PWMCHIP/pwm${IO_1}/duty_cycle dumpgptreg echo "###### High setting##" echo 43980465100800 > /sys/class/pwm/$PWMCHIP/pwm${IO_1}/period echo 23980465100800 > /sys/class/pwm/$PWMCHIP/pwm${IO_1}/duty_cycle dumpgptreg with mul_u64_u32_div(): ###### Medium setting 11000 sec = 3hours ## Read at address 0x10048464 (0xffffb9426464): 0x400746FE Read at address 0x1004844C (0xffff8fdfb44c): 0x2003A37F Read at address 0x1004842C (0xffff9855b42c): 0x05000001 ###### High setting## Read at address 0x10048464 (0xffff9101b464): 0xFFFFFFFF Read at address 0x1004844C (0xffffaee0544c): 0x8B95AD77 Read at address 0x1004842C (0xffffbbc8a42c): 0x05000001 with mul_u64_u64_div_u64(): ###### Medium setting 11000 sec = 3hours ## Read at address 0x10048464 (0xffffb3185464): 0x400746FE Read at address 0x1004844C (0xffff81ebb44c): 0x2003A37F Read at address 0x1004842C (0xffff904fd42c): 0x05000001 ######[ 304.213944] pwm-rzg2l-gpt 10048000.pwm: .apply is not idempotent (ena=1 pol=0 5500000000000/43980352512000) -> (ena=1 pol=0 5500000000000/43980239923200) High setting## [ 304.230854] pwm-rzg2l-gpt 10048000.pwm: .apply is not idempotent (ena=1 pol=0 23980465100800/43980352512000) -> (ena=1 pol=0 23980465100800/43980239923200) Read at address 0x10048464 (0xffffb5bb3464): 0xFFFFAA19 Read at address 0x1004844C (0xffff99b8c44c): 0x8B95AD77 Read at address 0x1004842C (0xffffbba2342c): 0x05000001 v15->v16: * Replaced the macro DIV_ROUND_UP_ULL->DIV64_U64_ROUND_UP * Added DIV_ROUND_UP in rzg2l_gpt_calculate_pv_or_dc() to avoid loss of precision. * Replaced min->min_t() in rzg2l_gpt_calculate_pv_or_dc(). * Added a comment for rzg2l_gpt_config() * Replaced mul_u64_u32_div()->mul_u64_u64_div_u64() in rzg2l_gpt_config() * Fixed the logical condition related to counter stop in rzg2l_gpt_config(). * Dropped pm_runtime_resume_*() from rzg2l_gpt_config() as it is managed by rzg2l_gpt_apply(). * Moved pm_runtime_resume_*() from rzg2l_gpt_{en,dis}able() to rzg2l_gpt_apply(). v14->v15: * Added enable_count and ch_en_bits variables to struct rzg2l_gpt_chip based on feedback for pwm_mtu3 driver. * Updated copyright header and commit description by replacing "This patch adds"-> "Add" * Replaced macro RZG2L_GET_CH_INDEX->RZG2L_GET_CH and replaced ch_index->ch throughout * rzg2l_gpt_{enable,disable}() enables/disables PWM based on the enable_count. * Replaced pm_runtime_get_sync->pm_runtime_resume_and_get and propogated the error in rzg2l_gpt_get_state() and rzg2l_gpt_config() * Reduced variable scope in rzg2l_gpt_get_state() by moving most of variables inside the if statement. * Updated rzg2l_gpt_get_state() by moving duty > period check inside the top if block. * Added helper functions rzg2l_gpt_calculate_pv_or_dc()to simplify config. Also Improved the logic in rzg2l_gpt_calculate_pv_or_dc() by using min(period_or_duty_cycle >> (2 * prescale), (u64)U32_MAX); * Updated rzg2l_gpt_get_state() by moving duty > period check inside the top if block. * Simplified rzg2l_gpt_config() for updating registers * Dropped pm_runtime_get_sync() and used bitmap variable "ch_en_bits" to make balanced PM usage count in rzg2l_gpt_reset_assert_pm_disable() For case were unbind is called before apply where pwm is enabled by bootloader. * Added error check for clk_rate_exclusive_get() and clk_get_rate() in probe(). * Dropped prescale from struct rzg2l_gpt_chip. * Replaced of_match_ptr(rzg2l_gpt_of_table)->rzg2l_gpt_of_table in struct rzg2l_gpt_driver * Updated commit description of patch#4 by replacing "This patch add"-> "Add". v13->v14: * Moved the patch from series[1] to here. [1] https://lore.kernel.org/linux-renesas-soc/20221215205843.4074504-1-biju.das.jz@bp.renesas.com/T/#t * Add Rb tag from Rob for patch#2 * Removed parenthesis for RZG2L_MAX_HW_CHANNELS and RZG2L_CHANNELS_PER_IO * Removed duty_cycle variable from struct rzg2l_gpt_chip and added comment for cache for prescale variable. * Fixed a bug in rzg2l_gpt_cntr_need_stop(). * Reordered rzg2l_gpt_config() just above apply() * Replaced pwm_is_enabled()->pwm->state.enabled in config * Replaced pm_runtime_resume_and_get with unconditional pm_runtime_get_sync() in config(). * Restored duty_cycle > period check in rzg2l_gpt_get_state(). * 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_get() * Simplified rzg2l_gpt_probe() by removing bitmap variables. * Added pm_runtime_idle() to suspend the device during probe. * Moved overflow condition check from config->probe(). * Simplified rzg2l_gpt_reset_assert_pm_disable(). * Removed the parenthesis for RZG2L_MAX_POEG_GROUPS. * Renamed rzg2l_gpt_parse_properties()->rzg2l_gpt_poeg_init() as it not only parse the properties but also implements the needed register writes. * Added acomment here about the purpose of the function rzg2l_gpt_poeg_init() * Removed magic numbers from rzg2l_gpt_poeg_init() * Fixed resource leak in rzg2l_gpt_poeg_init(). v12->v13: * Added test logs in [1] below * Replaced Kconfig dependency from ARCH_RENESAS->ARCH_RZG2L * Sorted #include alphabetically * Added a comment for mutex_lock to fix check patch warning * Replaced data type of duty_cycle from unsigned int->u32 as the maximum value stored is U32_MAX. * Improved rzg2l_gpt_config() by removing unwanted duty_cycle related code. * Improved rzg2l_gpt_get_state() by setting "val = rzg2l_gpt->duty_cycle[pwm->hwpwm];", and factor "tmp = NSEC_PER_SEC * (u64)val;" out of the if-statement. * Started using DEFINE_RUNTIME_DEV_PM_OPS(), and dropped __maybe_unused from the callbacks. v11->v12: * Added return code for get_state() * Cache duty cycle/prescale as the driver cannot read the current duty cycle/prescale from the hardware if the hardware is disabled. Cache the last programmed duty cycle/prescale value to return in that case. * Updated rzg2l_gpt_enable to enable the clocks. * Updated rzg2l_gpt_disable to disable the clocks. * Updated rzg2l_gpt_config() to cache duty cucle/prescale value * Updated rzg2l_gpt_get_state to use cached value of duty cycle/prescale,If the PWM is disabled. * Simplified rzg2l_gpt_apply() * Added comments in rzg2l_gpt_reset_assert_pm_disable() v10->v11: * Used bitmap_zero for initializing bitmap varable. * Fixed clock imbalance during remove for the case bootloader turning on PWM and module unload is called just after the boot. * Fixed over flow condition in get_state() for a prescale value of 2 & more. * Improved rzg2l_gpt_cntr_need_stop() based on prescale as it is the only runtime variable. * Added array for Cache variables state_period and prescale * Probe caches the prescale value set by the bootloader. * Updated rzg2l_gpt_config() to make use of array variables. v9->v10: * Updated the example gpt4: pwm@10048400-> gpt: pwm@10048000 * Keep Rb tag from Rob as the above change is trivial one. * Updated the error handling in probe(), clk_disable_unprepare called on the error path. * Removed ch_en array and started using bitmask instead. v8->v9: * Added Rb tag from Rob. * deassert after devm_clk_get() to avoid reset stays deasserted,in case clk_get() fails. * Removed ch_offs from struct rzg2l_gpt_chip and use macro instead. * Updated error handling in probe() v7->v8: * Removed Rb tags from Rob and Geert as it modelled as single GPT device handling multiple channels. * Updated description * Updated interrupts and interrupt-names properties * Updated binding example * Modelled as single PWM device handling multiple channels * Replaced shared reset->devm_reset_control_get_exclusive() * Added PM runtime callbacks * Updated PM handling and removed "pwm_enabled_by_bootloader" variable * Replaced iowrite32->writel and ioread32->readl * Updated prescale calculation * Introduced rzg2l_gpt_is_ch_enabled for checking enable status on both IO's * Moved enable/disable output pins from config->enable/disable. * Added rzg2l_gpt_cntr_need_stop() for caching prescalar/mode values. v6->v7: * Added the comment for cacheing rzg2l_gpt->state_period. * Fixed boundary values for pv and dc. * Added comment for modifying mode, prescaler, timer counter and buffer enable registers. * Fixed buffer overflow in get_state() * Removed unnecessary assignment of state->period value in get_state(). * Fixed state->duty_cycle value in get_state(). * Added a limitation for disabling the channels, when both channels used v5->v6: * Updated macros RZG2L_GTIOR_GTIOB_OUT_HI_END_TOGGLE_CMP_MATCH and RZG2L_GTIOR_GTIOB_OUT_LO_END_TOGGLE_CMP_MATCH with computation involving FIELD_PREP macro. * Removed struct rzg2l_gpt_phase and started using RZG2L_GTCCR macro for duty_offset. * replaced misnomer real_period->state_period. * Added handling for values >= (1024 << 32) for both period and duty cycle. * Added comments for pwm {en,dis}abled by bootloader during probe. v4->v5: * Added Hardware manual details * Replaced the comment GTCNT->Counter * Removed the macros RZG2L_GPT_IO_PER_CHANNEL and chip.npwm directly used in probe. * Removed the unsed macro RZG2L_GTPR_MAX_VALUE * Added driver prefix for the type name and the variable. * Initialization of per_channel data moved from request->probe. * Updated clr parameter for rzg2l_gpt_modify for Start count. * Started using mutex and usage_count for handling shared period and prescalar for the 2 channels. * Updated the comment cycle->period. * Removed clk_disable from rzg2l_gpt_reset_assert_pm_disable() * Replaced pc->rzg2l_gpt. * Updated prescale calculation. * Moved pm_runtime_{get_sync,put} from {request,free}->{enable,disable} * Removed platform_set_drvdata as it is unused * Removed the variable pwm_enabled_by_bootloader * Added dev_err_probe in various probe error path. * Added an error message, if devm_pwmchip_add fails. v3->v4: * Changed the local variable type i from u16->u8 and prescaled_period_ cycles from u64->u32 in calculate_prescale(). * Replaced mul_u64_u64_div_u64()->mul_u64_u32_div() * Dropped the comma after the sentinel. * Add a variable to track pwm enabled by bootloader and added comments in probe(). * Removed unnecessary rzg2l_gpt_reset_assert_pm_disable() from probe. * Replaced devm_clk_get()->devm_clk_get_prepared() * Removed devm_clk_get_optional_enabled() v2->v3: * Added Rb tag from Rob for the bindings. * Updated limitation section * Added prefix "RZG2L_" for all macros * Modified prescale calculation * Removed pwm_set_chip_data * Updated comment related to modifying Mode and Prescaler * Updated setting of prescale value in rzg2l_gpt_config() * Removed else branch from rzg2l_gpt_get_state() * removed the err label from rzg2l_gpt_apply() * Added devm_clk_get_optional_enabled() to retain clk on status, in case bootloader turns on the clk of pwm. * Replaced devm_reset_control_get_exclusive->devm_reset_control_get_shared as single reset shared between 8 channels. v1->v2: * Added '|' after 'description:' to preserve formatting. * Removed description for pwm_cells as it is common property. * Changed the reg size in example from 0xa4->0x100 * Added Rb tag from Geert for bindings. * Added Limitations section * dropped "_MASK" from the define names. * used named initializer for struct phase * Added gpt_pwm_device into a flexible array member in rzg2l_gpt_chip * Revised the logic for prescale * Added .get_state callback * Improved error handling in rzg2l_gpt_apply * Removed .remove callback * Tested the driver with PWM_DEBUG enabled. RFC->v1: * Added Description in binding patch * Removed comments from reg and clock * replaced rzg2l_gpt_write_mask()->rzg2l_gpt_modify() * Added rzg2l_gpt_read() and updated macros * Removed dtsi patches, will send it separately RFC: * https://lore.kernel.org/linux-renesas-soc/20220430075915.5036-1-biju.das.jz@bp.renesas.com/T/#t Biju Das (4): dt-bindings: pwm: Add RZ/G2L GPT binding dt-bindings: pwm: rzg2l-gpt: Document renesas,poegs property pwm: Add support for RZ/G2L GPT pwm: rzg2l-gpt: Add support for gpt linking with poeg .../bindings/pwm/renesas,rzg2l-gpt.yaml | 401 +++++++++++ drivers/pwm/Kconfig | 11 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-rzg2l-gpt.c | 655 ++++++++++++++++++ 4 files changed, 1068 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/renesas,rzg2l-gpt.yaml create mode 100644 drivers/pwm/pwm-rzg2l-gpt.c base-commit: d27abbfd4888d79dd24baf50e774631046ac4732