From a092f994e75c12530b593ff5917bd4cdd2cbf693 Mon Sep 17 00:00:00 2001 From: JiaY-shi Date: Wed, 6 Mar 2024 09:29:10 +0800 Subject: [PATCH] qualcommax: add pwm driver for ipq6018 Add PWM driver for IPQ6018 chipsets. Also, add support for pwm node in ipq6018. Signed-off-by: shi jiayang --- target/linux/qualcommax/config-6.1 | 3 + ...river-for-qualcomm-ipq6018-pwm-block.patch | 601 ++++++++++++++++++ ...-arm64-dts-qcom-ipq6018-add-pwm-node.patch | 187 ++++++ 3 files changed, 791 insertions(+) create mode 100644 target/linux/qualcommax/patches-6.1/0911-pwm-driver-for-qualcomm-ipq6018-pwm-block.patch create mode 100644 target/linux/qualcommax/patches-6.1/0912-arm64-dts-qcom-ipq6018-add-pwm-node.patch diff --git a/target/linux/qualcommax/config-6.1 b/target/linux/qualcommax/config-6.1 index acfdc99b22e8f1..b94932163a172e 100644 --- a/target/linux/qualcommax/config-6.1 +++ b/target/linux/qualcommax/config-6.1 @@ -357,6 +357,9 @@ CONFIG_POWER_SUPPLY=y CONFIG_PREEMPT_NONE_BUILD=y CONFIG_PRINTK_TIME=y CONFIG_PTP_1588_CLOCK_OPTIONAL=y +CONFIG_PWM=y +CONFIG_PWM_IPQ=y +CONFIG_PWM_SYSFS=y CONFIG_QCA807X_PHY=y CONFIG_QCA808X_PHY=y # CONFIG_QCM_DISPCC_2290 is not set diff --git a/target/linux/qualcommax/patches-6.1/0911-pwm-driver-for-qualcomm-ipq6018-pwm-block.patch b/target/linux/qualcommax/patches-6.1/0911-pwm-driver-for-qualcomm-ipq6018-pwm-block.patch new file mode 100644 index 00000000000000..0578b197426a4d --- /dev/null +++ b/target/linux/qualcommax/patches-6.1/0911-pwm-driver-for-qualcomm-ipq6018-pwm-block.patch @@ -0,0 +1,601 @@ +From patchwork Thu Oct 5 16:05:47 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +X-Patchwork-Submitter: Devi Priya +X-Patchwork-Id: 13410404 +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) + by smtp.lore.kernel.org (Postfix) with ESMTP id D89C1E92716 + for ; + Thu, 5 Oct 2023 16:21:19 +0000 (UTC) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S242346AbjJEQUu (ORCPT + ); + Thu, 5 Oct 2023 12:20:50 -0400 +Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34274 "EHLO + lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S242441AbjJEQR7 (ORCPT + ); + Thu, 5 Oct 2023 12:17:59 -0400 +Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com + [205.220.168.131]) + by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 654563F020; + Thu, 5 Oct 2023 09:06:56 -0700 (PDT) +Received: from pps.filterd (m0279862.ppops.net [127.0.0.1]) + by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id + 395Aarqd017488; + Thu, 5 Oct 2023 16:06:23 GMT +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; + h=from : to : cc : + subject : date : message-id : in-reply-to : references : mime-version : + content-type : content-transfer-encoding; s=qcppdkim1; + bh=pL305QZpgz9DE4v+JRgsjWEqf1lM32BSKRkIofAZtYI=; + b=N/VkHpLPyHQX0FtgqwJTY18MM5NIRAxm/+ejcJgF+GzogJXQJVrX/JAaY+GrGMI/jBWB + fXAGI3rifkl9eKUkW2WiW2CM3NLpeKa1XcRfGYC3FvWNeVEKpAdNUnneWq5jII/7rjwr + LOEF9iGjSkqgE38uQGz0bcm+TCePCLBym1xS29C8u1B7Xx0M74w+Du98muz8yAqjQbLM + xbUkhQ5rGl34cLkYMUaT8Zuu4Je14xfsUL+dVCk2/TppUvaqZz3mzOdGiwKGz9AWdnJ2 + 1+/sxswdw/5WhuALaDoCncbTHD0BtxYj3SYmNtE0+NHQ4IJ6rpa04qfytuU3+2V8h0xw FQ== +Received: from nalasppmta04.qualcomm.com (Global_NAT1.qualcomm.com + [129.46.96.20]) + by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3th8e1u8ty-1 + (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 + verify=NOT); + Thu, 05 Oct 2023 16:06:22 +0000 +Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com + [10.47.209.196]) + by NALASPPMTA04.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id + 395G6Lmf025392 + (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 + verify=NOT); + Thu, 5 Oct 2023 16:06:21 GMT +Received: from hu-devipriy-blr.qualcomm.com (10.80.80.8) by + nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server + (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id + 15.2.1118.36; Thu, 5 Oct 2023 09:06:16 -0700 +From: Devi Priya +To: , , + , , , + , , + , , + , , + , , + , +CC: , , + +Subject: [PATCH V15 1/4] pwm: driver for qualcomm ipq6018 pwm block +Date: Thu, 5 Oct 2023 21:35:47 +0530 +Message-ID: <20231005160550.2423075-2-quic_devipriy@quicinc.com> +X-Mailer: git-send-email 2.34.1 +In-Reply-To: <20231005160550.2423075-1-quic_devipriy@quicinc.com> +References: <20231005160550.2423075-1-quic_devipriy@quicinc.com> +MIME-Version: 1.0 +X-Originating-IP: [10.80.80.8] +X-ClientProxiedBy: nasanex01a.na.qualcomm.com (10.52.223.231) To + nalasex01a.na.qualcomm.com (10.47.209.196) +X-QCInternal: smtphost +X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 + signatures=585085 +X-Proofpoint-GUID: dUK910BXNf0cPwSxJTAoChM7COrWyzeE +X-Proofpoint-ORIG-GUID: dUK910BXNf0cPwSxJTAoChM7COrWyzeE +X-Proofpoint-Virus-Version: vendor=baseguard + engine=ICAP:2.0.267,Aquarius:18.0.980,Hydra:6.0.619,FMLib:17.11.176.26 + definitions=2023-10-05_11,2023-10-05_01,2023-05-22_02 +X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 + phishscore=0 suspectscore=0 + adultscore=0 priorityscore=1501 mlxscore=0 lowpriorityscore=0 spamscore=0 + bulkscore=0 mlxlogscore=999 malwarescore=0 impostorscore=0 clxscore=1015 + classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2309180000 + definitions=main-2310050126 +Precedence: bulk +List-ID: +X-Mailing-List: linux-arm-msm@vger.kernel.org + +Driver for the PWM block in Qualcomm IPQ6018 line of SoCs. Based on +driver from downstream Codeaurora kernel tree. Removed support for older +(V1) variants because I have no access to that hardware. + +Tested on IPQ6010 based hardware. + +Co-developed-by: Baruch Siach +Signed-off-by: Baruch Siach +Signed-off-by: Devi Priya +--- +V15: + No change + +V14: + No change + +V13: + No change + +V12: + + Fix the below clang warning for overflow check reported by kernel test robot + drivers/pwm/pwm-ipq.c:122:11: warning: result of comparison of constant 16000000000 + with expression of type 'unsigned long' is always false [-Wtautological-constant-out-of-range-compare] +>> if (rate > 16ULL * GIGA) + +v11: + +Address comment from Uwe Kleine-König: + + Drop redundant registers field comments + + Fix period limit check in .apply + + Clarify the comment explaining skip of pre_div > pwm_div values + + Add explicit check for clock rate within limit + + Add comment explaining the selection of initial pre_div + + Use pwm_div division with remainder instead of separate diff calculation + + Round up duty_cycle calculation in .get_state + +v10: + + Restore round up in pwm_div calculation; otherwise diff is always <= + 0, so only bingo match works + + Don't overwrite min_diff on every loop iteration + +v9: + +Address comment from Uwe Kleine-König: + + Use period_ns*rate in dividers calculation for better accuracy + + Round down pre_div and pwm_div + + Add a comment explaining why pwm_div can't underflow + + Add a comment explaining why pre_div > pwm_div end the search loop + + Drop 'CFG_' from register macros + + Rename to_ipq_pwm_chip() to ipq_pwm_from_chip() + + Change bare 'unsigned' to 'unsigned int' + + Clarify the comment on separate REG1 write for enable/disable + Round up the period value in .get_state + + Use direct readl/writel so no need to check for regmap errors + +v7: + + Change 'offset' to 'reg' for the tcsr offset (Rob) + + Drop clock name; there is only one clock (Bjorn) + + Simplify probe failure code path (Bjorn) + +v6: + +Address Uwe Kleine-König review comments: + + Drop IPQ_PWM_MAX_DEVICES + + Rely on assigned-clock-rates; drop IPQ_PWM_CLK_SRC_FREQ + + Simplify register offset calculation + + Calculate duty cycle more precisely + + Refuse to set inverted polarity + + Drop redundant IPQ_PWM_REG1_ENABLE bit clear + + Remove x1000 factor in pwm_div calculation, use rate directly, and round up + + Choose initial pre_div such that pwm_div < IPQ_PWM_MAX_DIV + + Ensure pre_div <= pwm_div + + Rename close_ to best_ + + Explain in comment why effective_div doesn't overflow + + Limit pwm_div to IPQ_PWM_MAX_DIV - 1 to allow 100% duty cycle + + Disable clock only after pwmchip_remove() + + const pwm_ops + +Other changes: + + Add missing linux/bitfield.h header include (kernel test robot) + + Adjust code for PWM device node under TCSR (Rob Herring) + +v5: + + Use &tcsr_q6 syscon to access registers (Bjorn Andersson) + + Address Uwe Kleine-König review comments: + + Implement .get_state() + + Add IPQ_PWM_ prefix to local macros + + Use GENMASK/BIT/FIELD_PREP for register fields access + + Make type of config_div_and_duty() parameters consistent + + Derive IPQ_PWM_MIN_PERIOD_NS from IPQ_PWM_CLK_SRC_FREQ + + Integrate enable/disable into config_div_and_duty() to save register read, + and reduce frequency glitch on update + + Use min() instead of min_t() + + Fix comment format + + Use dev_err_probe() to indicate probe step failure + + Add missing clk_disable_unprepare() in .remove + + Don't set .owner + +v4: + + Use div64_u64() to fix link for 32-bit targets ((kernel test robot + , Uwe Kleine-König) + +v3: + + s/qcom,pwm-ipq6018/qcom,ipq6018-pwm/ (Rob Herring) + + Fix integer overflow on 32-bit targets (kernel test robot ) + +v2: + +Address Uwe Kleine-König review comments: + + Fix period calculation when out of range + + Don't set period larger than requested + + Remove PWM disable on configuration change + + Implement .apply instead of non-atomic .config/.enable/.disable + + Don't modify PWM on .request/.free + + Check pwm_div underflow + + Fix various code and comment formatting issues + +Other changes: + + Use u64 divisor safe division + + Remove now empty .request/.free + + drivers/pwm/Kconfig | 12 ++ + drivers/pwm/Makefile | 1 + + drivers/pwm/pwm-ipq.c | 282 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 295 insertions(+) + create mode 100644 drivers/pwm/pwm-ipq.c + +--- a/drivers/pwm/Kconfig ++++ b/drivers/pwm/Kconfig +@@ -270,6 +270,18 @@ config PWM_INTEL_LGM + To compile this driver as a module, choose M here: the module + will be called pwm-intel-lgm. + ++config PWM_IPQ ++ tristate "IPQ PWM support" ++ depends on ARCH_QCOM || COMPILE_TEST ++ depends on HAVE_CLK && HAS_IOMEM ++ help ++ Generic PWM framework driver for IPQ PWM block which supports ++ 4 pwm channels. Each of the these channels can be configured ++ independent of each other. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm-ipq. ++ + config PWM_IQS620A + tristate "Azoteq IQS620A PWM support" + depends on MFD_IQS62X || COMPILE_TEST +--- a/drivers/pwm/Makefile ++++ b/drivers/pwm/Makefile +@@ -23,6 +23,7 @@ obj-$(CONFIG_PWM_IMX1) += pwm-imx1.o + obj-$(CONFIG_PWM_IMX27) += pwm-imx27.o + obj-$(CONFIG_PWM_IMX_TPM) += pwm-imx-tpm.o + obj-$(CONFIG_PWM_INTEL_LGM) += pwm-intel-lgm.o ++obj-$(CONFIG_PWM_IPQ) += pwm-ipq.o + obj-$(CONFIG_PWM_IQS620A) += pwm-iqs620a.o + obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o + obj-$(CONFIG_PWM_KEEMBAY) += pwm-keembay.o +--- /dev/null ++++ b/drivers/pwm/pwm-ipq.c +@@ -0,0 +1,282 @@ ++// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 ++/* ++ * Copyright (c) 2016-2017, 2020 The Linux Foundation. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* The frequency range supported is 1 Hz to clock rate */ ++#define IPQ_PWM_MAX_PERIOD_NS ((u64)NSEC_PER_SEC) ++ ++/* ++ * The max value specified for each field is based on the number of bits ++ * in the pwm control register for that field ++ */ ++#define IPQ_PWM_MAX_DIV 0xFFFF ++ ++/* ++ * Two 32-bit registers for each PWM: REG0, and REG1. ++ * Base offset for PWM #i is at 8 * #i. ++ */ ++#define IPQ_PWM_REG0 0 ++#define IPQ_PWM_REG0_PWM_DIV GENMASK(15, 0) ++#define IPQ_PWM_REG0_HI_DURATION GENMASK(31, 16) ++ ++#define IPQ_PWM_REG1 4 ++#define IPQ_PWM_REG1_PRE_DIV GENMASK(15, 0) ++/* ++ * Enable bit is set to enable output toggling in pwm device. ++ * Update bit is set to reflect the changed divider and high duration ++ * values in register. ++ */ ++#define IPQ_PWM_REG1_UPDATE BIT(30) ++#define IPQ_PWM_REG1_ENABLE BIT(31) ++ ++struct ipq_pwm_chip { ++ struct pwm_chip chip; ++ struct clk *clk; ++ void __iomem *mem; ++}; ++ ++static struct ipq_pwm_chip *ipq_pwm_from_chip(struct pwm_chip *chip) ++{ ++ return container_of(chip, struct ipq_pwm_chip, chip); ++} ++ ++static unsigned int ipq_pwm_reg_read(struct pwm_device *pwm, unsigned int reg) ++{ ++ struct ipq_pwm_chip *ipq_chip = ipq_pwm_from_chip(pwm->chip); ++ unsigned int off = 8 * pwm->hwpwm + reg; ++ ++ return readl(ipq_chip->mem + off); ++} ++ ++static void ipq_pwm_reg_write(struct pwm_device *pwm, unsigned int reg, ++ unsigned int val) ++{ ++ struct ipq_pwm_chip *ipq_chip = ipq_pwm_from_chip(pwm->chip); ++ unsigned int off = 8 * pwm->hwpwm + reg; ++ ++ writel(val, ipq_chip->mem + off); ++} ++ ++static void config_div_and_duty(struct pwm_device *pwm, unsigned int pre_div, ++ unsigned int pwm_div, unsigned long rate, u64 duty_ns, ++ bool enable) ++{ ++ unsigned long hi_dur; ++ unsigned long val = 0; ++ ++ /* ++ * high duration = pwm duty * (pwm div + 1) ++ * pwm duty = duty_ns / period_ns ++ */ ++ hi_dur = div64_u64(duty_ns * rate, (pre_div + 1) * NSEC_PER_SEC); ++ ++ val = FIELD_PREP(IPQ_PWM_REG0_HI_DURATION, hi_dur) | ++ FIELD_PREP(IPQ_PWM_REG0_PWM_DIV, pwm_div); ++ ipq_pwm_reg_write(pwm, IPQ_PWM_REG0, val); ++ ++ val = FIELD_PREP(IPQ_PWM_REG1_PRE_DIV, pre_div); ++ ipq_pwm_reg_write(pwm, IPQ_PWM_REG1, val); ++ ++ /* PWM enable toggle needs a separate write to REG1 */ ++ val |= IPQ_PWM_REG1_UPDATE; ++ if (enable) ++ val |= IPQ_PWM_REG1_ENABLE; ++ ipq_pwm_reg_write(pwm, IPQ_PWM_REG1, val); ++} ++ ++static int ipq_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ++ const struct pwm_state *state) ++{ ++ struct ipq_pwm_chip *ipq_chip = ipq_pwm_from_chip(chip); ++ unsigned int pre_div, pwm_div, best_pre_div, best_pwm_div; ++ unsigned long rate = clk_get_rate(ipq_chip->clk); ++ u64 period_ns, duty_ns, period_rate; ++ u64 min_diff; ++ ++ if (state->polarity != PWM_POLARITY_NORMAL) ++ return -EINVAL; ++ ++ if (state->period < DIV64_U64_ROUND_UP(NSEC_PER_SEC, rate)) ++ return -ERANGE; ++ ++ period_ns = min(state->period, IPQ_PWM_MAX_PERIOD_NS); ++ duty_ns = min(state->duty_cycle, period_ns); ++ ++ /* ++ * period_ns is 1G or less. As long as rate is less than 16 GHz, ++ * period_rate does not overflow. Make that explicit. ++ */ ++ if ((unsigned long long)rate > 16ULL * GIGA) ++ return -EINVAL; ++ period_rate = period_ns * rate; ++ best_pre_div = IPQ_PWM_MAX_DIV; ++ best_pwm_div = IPQ_PWM_MAX_DIV; ++ /* ++ * We don't need to consider pre_div values smaller than ++ * ++ * period_rate ++ * pre_div_min := ------------------------------------ ++ * NSEC_PER_SEC * (IPQ_PWM_MAX_DIV + 1) ++ * ++ * because pre_div = pre_div_min results in a better ++ * approximation. ++ */ ++ pre_div = div64_u64(period_rate, ++ (u64)NSEC_PER_SEC * (IPQ_PWM_MAX_DIV + 1)); ++ min_diff = period_rate; ++ ++ for (; pre_div <= IPQ_PWM_MAX_DIV; pre_div++) { ++ u64 remainder; ++ ++ pwm_div = div64_u64_rem(period_rate, ++ (u64)NSEC_PER_SEC * (pre_div + 1), &remainder); ++ /* pwm_div is unsigned; the check below catches underflow */ ++ pwm_div--; ++ ++ /* ++ * Swapping values for pre_div and pwm_div produces the same ++ * period length. So we can skip all settings with pre_div > ++ * pwm_div which results in bigger constraints for selecting ++ * the duty_cycle than with the two values swapped. ++ */ ++ if (pre_div > pwm_div) ++ break; ++ ++ /* ++ * Make sure we can do 100% duty cycle where ++ * hi_dur == pwm_div + 1 ++ */ ++ if (pwm_div > IPQ_PWM_MAX_DIV - 1) ++ continue; ++ ++ if (remainder < min_diff) { ++ best_pre_div = pre_div; ++ best_pwm_div = pwm_div; ++ min_diff = remainder; ++ ++ if (min_diff == 0) /* bingo */ ++ break; ++ } ++ } ++ ++ /* config divider values for the closest possible frequency */ ++ config_div_and_duty(pwm, best_pre_div, best_pwm_div, ++ rate, duty_ns, state->enabled); ++ ++ return 0; ++} ++ ++static int ipq_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, ++ struct pwm_state *state) ++{ ++ struct ipq_pwm_chip *ipq_chip = ipq_pwm_from_chip(chip); ++ unsigned long rate = clk_get_rate(ipq_chip->clk); ++ unsigned int pre_div, pwm_div, hi_dur; ++ u64 effective_div, hi_div; ++ u32 reg0, reg1; ++ ++ reg0 = ipq_pwm_reg_read(pwm, IPQ_PWM_REG0); ++ reg1 = ipq_pwm_reg_read(pwm, IPQ_PWM_REG1); ++ ++ state->polarity = PWM_POLARITY_NORMAL; ++ state->enabled = reg1 & IPQ_PWM_REG1_ENABLE; ++ ++ pwm_div = FIELD_GET(IPQ_PWM_REG0_PWM_DIV, reg0); ++ hi_dur = FIELD_GET(IPQ_PWM_REG0_HI_DURATION, reg0); ++ pre_div = FIELD_GET(IPQ_PWM_REG1_PRE_DIV, reg1); ++ ++ /* No overflow here, both pre_div and pwm_div <= 0xffff */ ++ effective_div = (u64)(pre_div + 1) * (pwm_div + 1); ++ state->period = DIV64_U64_ROUND_UP(effective_div * NSEC_PER_SEC, rate); ++ ++ hi_div = hi_dur * (pre_div + 1); ++ state->duty_cycle = DIV64_U64_ROUND_UP(hi_div * NSEC_PER_SEC, rate); ++ ++ return 0; ++} ++ ++static const struct pwm_ops ipq_pwm_ops = { ++ .apply = ipq_pwm_apply, ++ .get_state = ipq_pwm_get_state, ++ .owner = THIS_MODULE, ++}; ++ ++static int ipq_pwm_probe(struct platform_device *pdev) ++{ ++ struct ipq_pwm_chip *pwm; ++ struct device *dev = &pdev->dev; ++ int ret; ++ ++ pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL); ++ if (!pwm) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, pwm); ++ ++ pwm->mem = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(pwm->mem)) ++ return dev_err_probe(dev, PTR_ERR(pwm->mem), ++ "regs map failed"); ++ ++ pwm->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(pwm->clk)) ++ return dev_err_probe(dev, PTR_ERR(pwm->clk), ++ "failed to get clock"); ++ ++ ret = clk_prepare_enable(pwm->clk); ++ if (ret) ++ return dev_err_probe(dev, ret, "clock enable failed"); ++ ++ pwm->chip.dev = dev; ++ pwm->chip.ops = &ipq_pwm_ops; ++ pwm->chip.npwm = 4; ++ ++ ret = pwmchip_add(&pwm->chip); ++ if (ret < 0) { ++ dev_err_probe(dev, ret, "pwmchip_add() failed\n"); ++ clk_disable_unprepare(pwm->clk); ++ } ++ ++ return ret; ++} ++ ++static int ipq_pwm_remove(struct platform_device *pdev) ++{ ++ struct ipq_pwm_chip *pwm = platform_get_drvdata(pdev); ++ ++ pwmchip_remove(&pwm->chip); ++ clk_disable_unprepare(pwm->clk); ++ ++ return 0; ++} ++ ++static const struct of_device_id pwm_ipq_dt_match[] = { ++ { .compatible = "qcom,ipq6018-pwm", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, pwm_ipq_dt_match); ++ ++static struct platform_driver ipq_pwm_driver = { ++ .driver = { ++ .name = "ipq-pwm", ++ .of_match_table = pwm_ipq_dt_match, ++ }, ++ .probe = ipq_pwm_probe, ++ .remove = ipq_pwm_remove, ++}; ++ ++module_platform_driver(ipq_pwm_driver); ++ ++MODULE_LICENSE("Dual BSD/GPL"); diff --git a/target/linux/qualcommax/patches-6.1/0912-arm64-dts-qcom-ipq6018-add-pwm-node.patch b/target/linux/qualcommax/patches-6.1/0912-arm64-dts-qcom-ipq6018-add-pwm-node.patch new file mode 100644 index 00000000000000..28102751a1b857 --- /dev/null +++ b/target/linux/qualcommax/patches-6.1/0912-arm64-dts-qcom-ipq6018-add-pwm-node.patch @@ -0,0 +1,187 @@ +From patchwork Thu Oct 5 16:05:50 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +X-Patchwork-Submitter: Devi Priya +X-Patchwork-Id: 13410402 +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) + by smtp.lore.kernel.org (Postfix) with ESMTP id 0A952E71D4F + for ; + Thu, 5 Oct 2023 16:21:13 +0000 (UTC) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S242309AbjJEQUs (ORCPT + ); + Thu, 5 Oct 2023 12:20:48 -0400 +Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36106 "EHLO + lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S242451AbjJEQSB (ORCPT + ); + Thu, 5 Oct 2023 12:18:01 -0400 +Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com + [205.220.180.131]) + by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C6E8D3F025; + Thu, 5 Oct 2023 09:06:56 -0700 (PDT) +Received: from pps.filterd (m0279869.ppops.net [127.0.0.1]) + by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id + 395CsRur015464; + Thu, 5 Oct 2023 16:06:41 GMT +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; + h=from : to : cc : + subject : date : message-id : in-reply-to : references : mime-version : + content-type : content-transfer-encoding; s=qcppdkim1; + bh=NSi6brrY0QDAZ3HzHxPaf2hgz27vKeKX8LZRRHNWQWc=; + b=bhnUe3rjnlfJlfGglxvqihGmTNQCt2GnP9fbZBkIsYd0LKp5VGtAlA0IYUcwsiTLb7RK + zTJfR/Llub7KabA70G7qxopCKO0GgBFRq3Xhug1Nnrpr08qcHCrAOSuS16i8viiv5tE/ + Lrn3/Dj59DKIWaBWzrTmI5pK0eLkK0nAPYsTjv03eE8JFtw3M0lHrMQdjuwtpNE7ivjl + CCkahl9YDirevdy+EdeBg17dBw4R3t/qo+3tDzom1COe5knM5DIJI79fxqY1ueFFOM6D + D5mVEsufaOcEQFeLv3y7PtEsPTmWdyN2PCiU8GpFFz6KH8iJLyhzHc6o5pItDDupV1EG uQ== +Received: from nalasppmta04.qualcomm.com (Global_NAT1.qualcomm.com + [129.46.96.20]) + by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3thn059cyw-1 + (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 + verify=NOT); + Thu, 05 Oct 2023 16:06:41 +0000 +Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com + [10.47.209.196]) + by NALASPPMTA04.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id + 395G6dfE025540 + (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 + verify=NOT); + Thu, 5 Oct 2023 16:06:40 GMT +Received: from hu-devipriy-blr.qualcomm.com (10.80.80.8) by + nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server + (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id + 15.2.1118.36; Thu, 5 Oct 2023 09:06:34 -0700 +From: Devi Priya +To: , , + , , , + , , + , , + , , + , , + , +CC: , , + +Subject: [PATCH V15 4/4] arm64: dts: qcom: ipq6018: add pwm node +Date: Thu, 5 Oct 2023 21:35:50 +0530 +Message-ID: <20231005160550.2423075-5-quic_devipriy@quicinc.com> +X-Mailer: git-send-email 2.34.1 +In-Reply-To: <20231005160550.2423075-1-quic_devipriy@quicinc.com> +References: <20231005160550.2423075-1-quic_devipriy@quicinc.com> +MIME-Version: 1.0 +X-Originating-IP: [10.80.80.8] +X-ClientProxiedBy: nasanex01a.na.qualcomm.com (10.52.223.231) To + nalasex01a.na.qualcomm.com (10.47.209.196) +X-QCInternal: smtphost +X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 + signatures=585085 +X-Proofpoint-ORIG-GUID: pbCgYn8v-0OpdxaoHvIbH76mglvWkJsO +X-Proofpoint-GUID: pbCgYn8v-0OpdxaoHvIbH76mglvWkJsO +X-Proofpoint-Virus-Version: vendor=baseguard + engine=ICAP:2.0.267,Aquarius:18.0.980,Hydra:6.0.619,FMLib:17.11.176.26 + definitions=2023-10-05_11,2023-10-05_01,2023-05-22_02 +X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 + adultscore=0 suspectscore=0 + impostorscore=0 bulkscore=0 spamscore=0 mlxlogscore=999 priorityscore=1501 + mlxscore=0 malwarescore=0 lowpriorityscore=0 phishscore=0 clxscore=1015 + classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2309180000 + definitions=main-2310050125 +Precedence: bulk +List-ID: +X-Mailing-List: linux-arm-msm@vger.kernel.org + +Describe the PWM block on IPQ6018. + +The PWM is in the TCSR area. Make &tcsr "simple-mfd" compatible, and add +&pwm as child of &tcsr. + +Add also ipq6018 specific compatible string. + +Reviewed-by: Krzysztof Kozlowski +Co-developed-by: Baruch Siach +Signed-off-by: Baruch Siach +Signed-off-by: Devi Priya +--- +v15: + + Fixed the indentation of pwm node + +v14: + + Moved ranges just after reg as suggested by Krzysztof + + Picked up the R-b tag + +v13: + + No change + +v12: + + No change + +v11: + + No change + +v10: + + No change + +v9: + + Add 'ranges' property (Rob) + +v8: + + Add size cell to 'reg' (Rob) + +v7: + + Use 'reg' instead of 'offset' (Rob) + + Add qcom,tcsr-ipq6018 (Rob) + + Drop clock-names (Bjorn) + +v6: + + Make the PWM node child of TCSR (Rob Herring) + + Add assigned-clocks/assigned-clock-rates (Uwe Kleine-König) + +v5: Use qcom,pwm-regs for TCSR phandle instead of direct regs + +v3: s/qcom,pwm-ipq6018/qcom,ipq6018-pwm/ (Rob Herring) + + arch/arm64/boot/dts/qcom/ipq6018.dtsi | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi ++++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi +@@ -456,8 +456,21 @@ + }; + + tcsr: syscon@1937000 { +- compatible = "qcom,tcsr-ipq6018", "syscon"; ++ compatible = "qcom,tcsr-ipq6018", "syscon", "simple-mfd"; + reg = <0x0 0x01937000 0x0 0x21000>; ++ ranges = <0x0 0x0 0x01937000 0x21000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ pwm: pwm@a010 { ++ compatible = "qcom,ipq6018-pwm"; ++ reg = <0xa010 0x20>; ++ clocks = <&gcc GCC_ADSS_PWM_CLK>; ++ assigned-clocks = <&gcc GCC_ADSS_PWM_CLK>; ++ assigned-clock-rates = <100000000>; ++ #pwm-cells = <2>; ++ status = "disabled"; ++ }; + }; + + usb2: usb@70f8800 { \ No newline at end of file