Merge branch 'CR_871_PWM_hal.feng' into 'jh7110_fpga_dev_5.15'
authorandy.hu <andy.hu@starfivetech.com>
Mon, 25 Apr 2022 10:09:25 +0000 (10:09 +0000)
committerandy.hu <andy.hu@starfivetech.com>
Mon, 25 Apr 2022 10:09:25 +0000 (10:09 +0000)
Cr 871 pwm hal.feng

See merge request sdk/sft-riscvpi-linux-5.10!28

arch/riscv/boot/dts/starfive/jh7110.dtsi
arch/riscv/boot/dts/starfive/jh7110_pinctrl.dtsi
drivers/pwm/pwm-starfive-ptc.c

index 410458a..db0049e 100644 (file)
                        compatible = "starfive,pwm0";
                        reg = <0x0 0x120d0000 0x0 0x10000>;
                        reg-names = "control";
-                       clocks = <&pwmclk>;
-                       sifive,approx-period = <1000000>;
+                       clocks = <&clkgen JH7110_PWM_CLK_APB>;
+                       resets = <&rstgen RSTN_U0_PWM_8CH_APB>;
+                       starfive,approx-period = <2000000>;
                        #pwm-cells=<3>;
-                       sifive,npwm = <8>;
+                       starfive,npwm = <8>;
                        status = "disabled";
                };
 
index d7de75f..57c5629 100644 (file)
        status = "okay";
 };
 
+&ptc {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pwm_ch0_pins>;
+       status = "okay";
+};
+
 &sdio0 {
        pinctrl-names = "default";
        pinctrl-0 = <&mmc0_pins>;
index 19015a6..a61a5fa 100644 (file)
@@ -1,9 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (C) 2018 Starfive, Inc
+ * Copyright (C) 2018 StarFive, Inc
  *
  * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2, as published by
- * the Free Software Foundation.
+ * under the terms of the GNU General Public License version 2, as published
+ * by the Free Software Foundation.
  */
 
 #include <dt-bindings/pwm/pwm.h>
 #include <linux/pwm.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
+#include <linux/reset.h>
 #include <linux/io.h>
 
 /* max channel of pwm */
 #define MAX_PWM                                                        8
 
 /* PTC Register offsets */
-#define REG_RPTC_CNTR                                          0x0
+#define REG_RPTC_CNTR                                          0x0
 #define REG_RPTC_HRC                                           0x4
 #define REG_RPTC_LRC                                           0x8
 #define REG_RPTC_CTRL                                          0xC
 
 #define PTC_DEBUG                                              0
 
-/* Access PTC register (cntr hrc lrc and ctrl) ,need to replace PWM_BASE_ADDR */
-#define REG_PTC_BASE_ADDR_SUB(base, N)         ((base) + ((N>3)?((N%4)*0x10+(1<<15)):(N*0x10))) 
-#define REG_PTC_RPTC_CNTR(base,N)              (REG_PTC_BASE_ADDR_SUB(base,N))
-#define REG_PTC_RPTC_HRC(base,N)               (REG_PTC_BASE_ADDR_SUB(base,N) + 0x4)
-#define REG_PTC_RPTC_LRC(base,N)               (REG_PTC_BASE_ADDR_SUB(base,N) + 0x8)
-#define REG_PTC_RPTC_CTRL(base,N)              (REG_PTC_BASE_ADDR_SUB(base,N) + 0xC)
-
-///PTC_RPTC_CTRL
-#define PTC_EN      (1<<0)
-#define PTC_ECLK    (1<<1)  /* 1:ptc_ecgt signal increment RPTC_CNTR. 0:system clock increment RPTC_CNTR. */
-#define PTC_NEC     (1<<2)  /* gate:system clock or ptc_ecgt input signal to increment RPTC_CNTR. If gate function is enabled, PWM periods can be automatically adjusted with the capture input. */
-#define PTC_OE      (1<<3)  /* enbale PWM output */
-#define PTC_SIGNLE  (1<<4)  /* 1:single operation; 0:continue operation */
-#define PTC_INTE    (1<<5)  /* Timer/Counter interrput enable */
-#define PTC_INT     (1<<6)  /* interrupt status, write 1 to clear */
-#define PTC_CNTRRST (1<<7)  /* 0:clear reset */
-#define PTC_CAPTE   (1<<8)  /* ptc_capt to increment RPTC_CNTR.*/
-
+/*
+ * Access PTC register (cntr hrc lrc and ctrl),
+ * need to replace PWM_BASE_ADDR
+ */
+#define REG_PTC_BASE_ADDR_SUB(base, N) \
+((base) + (((N) > 3) ? (((N) % 4) * 0x10 + (1 << 15)) : ((N) * 0x10)))
+#define REG_PTC_RPTC_CNTR(base, N)     (REG_PTC_BASE_ADDR_SUB(base, N))
+#define REG_PTC_RPTC_HRC(base, N)      (REG_PTC_BASE_ADDR_SUB(base, N) + 0x4)
+#define REG_PTC_RPTC_LRC(base, N)      (REG_PTC_BASE_ADDR_SUB(base, N) + 0x8)
+#define REG_PTC_RPTC_CTRL(base, N)     (REG_PTC_BASE_ADDR_SUB(base, N) + 0xC)
+
+/* PTC_RPTC_CTRL */
+#define PTC_EN      BIT(0)
+#define PTC_ECLK    BIT(1)
+#define PTC_NEC     BIT(2)
+#define PTC_OE      BIT(3)
+#define PTC_SIGNLE  BIT(4)
+#define PTC_INTE    BIT(5)
+#define PTC_INT     BIT(6)
+#define PTC_CNTRRST BIT(7)
+#define PTC_CAPTE   BIT(8)
 
 /* pwm ptc device */
 struct starfive_pwm_ptc_device {
        struct pwm_chip         chip;
        struct clk              *clk;
+       struct reset_control    *rst;
        void __iomem            *regs;
-       int                     irq;
-       /* apb clock frequency , from dts */
+       int                     irq;
+       /* apb clock frequency, from dts */
        unsigned int            approx_period;
 };
 
-static inline struct starfive_pwm_ptc_device *chip_to_starfive_ptc(struct pwm_chip *c)
+static inline struct starfive_pwm_ptc_device *
+chip_to_starfive_ptc(struct pwm_chip *c)
 {
        return container_of(c, struct starfive_pwm_ptc_device, chip);
 }
 
-
-static void starfive_pwm_ptc_get_state(struct pwm_chip *chip, struct pwm_device *dev, struct pwm_state *state)
+static void starfive_pwm_ptc_get_state(struct pwm_chip *chip,
+                                      struct pwm_device *dev,
+                                      struct pwm_state *state)
 {
        struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip);
-       uint32_t data_lrc;
-       uint32_t data_hrc;
-       uint32_t period;        
-       uint32_t pwm_clk_ns = 0;
+       u32 data_lrc;
+       u32 data_hrc;
+       u32 period;
+       u32 pwm_clk_ns = 0;
 
        /* get lrc and hrc data from registe*/
-       data_lrc = ioread32(REG_PTC_RPTC_LRC(pwm->regs,dev->hwpwm));
-       data_hrc = ioread32(REG_PTC_RPTC_HRC(pwm->regs,dev->hwpwm));
-       //period = data_lrc + data_hrc;
+       data_lrc = ioread32(REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm));
+       data_hrc = ioread32(REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm));
 
        /* how many ns does apb clock elapse */
        pwm_clk_ns = NS_1 / pwm->approx_period;
 
        /* pwm period(ns) */
-       state->period     = data_lrc*pwm_clk_ns;
+       state->period = data_lrc * pwm_clk_ns;
 
-       /* duty cycle(ns) ,means high level eclapse ns if it is normal polarity */
-       state->duty_cycle = data_hrc*pwm_clk_ns;
+       /* duty cycle(ns)means high level eclapse ns if it is normal polarity */
+       state->duty_cycle = data_hrc * pwm_clk_ns;
 
-       /* polarity,we don't use it now because it is not in dts */
-       state->polarity   = PWM_POLARITY_NORMAL;
+       /* polarity, we don't use it now because it is not in dts */
+       state->polarity = PWM_POLARITY_NORMAL;
 
        /* enabled or not */
-       state->enabled    = 1;
-#if PTC_DEBUG   
-       printk("starfive_pwm_ptc_get_state in,no:%d....\r\n",dev->hwpwm);
-       printk("data_hrc:0x%x 0x%x \n", data_hrc, data_lrc);
-       printk("period:%d\r\n",state->period);
-       printk("duty_cycle:%d\r\n",state->duty_cycle);
-       printk("polarity:%d\r\n",state->polarity);
-       printk("enabled:%d\r\n",state->enabled);
+       state->enabled = 1;
+#if PTC_DEBUG
+       dev_info(chip->dev, "%s in,no:%d....\r\n", __func__, dev->hwpwm);
+       dev_info(chip->dev, "data_hrc:0x%x 0x%x\n", data_hrc, data_lrc);
+       dev_info(chip->dev, "period:%d\r\n", state->period);
+       dev_info(chip->dev, "duty_cycle:%d\r\n", state->duty_cycle);
+       dev_info(chip->dev, "polarity:%d\r\n", state->polarity);
+       dev_info(chip->dev, "enabled:%d\r\n", state->enabled);
 #endif
-
 }
 
-
-static int starfive_pwm_ptc_apply(struct pwm_chip *chip, struct pwm_device *dev, struct pwm_state *state)
+static int starfive_pwm_ptc_apply(struct pwm_chip *chip,
+                                 struct pwm_device *dev,
+                                 struct pwm_state *state)
 {
        struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip);
-       uint32_t pwm_clk_ns = 0;
-       uint32_t data_hrc = 0;
-       uint32_t data_lrc = 0;
-       uint32_t period_data = 0;
-       uint32_t duty_data = 0;
-       void __iomemreg_addr;
-
-#if PTC_DEBUG  
-       printk("starfive_pwm_ptc_apply in,no:%d....\r\n",dev->hwpwm);
-       printk("set parameter......\r\n");
-       printk("period:%d\r\n",state->period);
-       printk("duty_cycle:%d\r\n",state->duty_cycle);  
-       printk("polarity:%d\r\n",state->polarity);
-       printk("enabled:%d\r\n",state->enabled);
+       u32 pwm_clk_ns = 0;
+       u32 data_hrc = 0;
+       u32 data_lrc = 0;
+       u32 period_data = 0;
+       u32 duty_data = 0;
+       void __iomem *reg_addr;
+
+#if PTC_DEBUG
+       dev_info(chip->dev, "%s in,no:%d....\r\n", __func__, dev->hwpwm);
+       dev_info(chip->dev, "set parameter......\r\n");
+       dev_info(chip->dev, "period:%d\r\n", state->period);
+       dev_info(chip->dev, "duty_cycle:%d\r\n", state->duty_cycle);
+       dev_info(chip->dev, "polarity:%d\r\n", state->polarity);
+       dev_info(chip->dev, "enabled:%d\r\n", state->enabled);
 #endif
        /* duty_cycle should be less or equal than period */
-       if(state->duty_cycle > state->period)
-       {
+       if (state->duty_cycle > state->period)
                state->duty_cycle = state->period;
-       }       
 
        /* calculate pwm real period (ns) */
        pwm_clk_ns = NS_1 / pwm->approx_period;
-       
+
 #if PTC_DEBUG
-       printk("approx_period,:%d,pwm_clk_ns:%d\r\n",pwm->approx_period,pwm_clk_ns);
+       dev_info(chip->dev, "approx_period,:%d,pwm_clk_ns:%d\r\n",
+                pwm->approx_period, pwm_clk_ns);
 #endif
 
        /* calculate period count */
        period_data = state->period / pwm_clk_ns;
 
-       if (!state->enabled) 
-       {
-               /* if is unenable,just set duty_dat to 0 , means low level always */
+       if (!state->enabled) {
+               /* if is unenable, just set duty_dat to 0, means low level always */
                duty_data = 0;
-       }
-       else
-       {
+       } else {
                /* calculate duty count*/
                duty_data = state->duty_cycle / pwm_clk_ns;
        }
 
 #if PTC_DEBUG
-       printk("period_data:%d,duty_data:%d\r\n",period_data,duty_data);
+       dev_info(chip->dev, "period_data:%d,duty_data:%d\r\n",
+                period_data, duty_data);
 #endif
 
-       if(state->polarity == PWM_POLARITY_NORMAL)
-       {
-               /* calculate data_hrc */        
-               data_hrc = period_data - duty_data;             
-       }
-       else
-       {
+       if (state->polarity == PWM_POLARITY_NORMAL) {
+               /* calculate data_hrc */
+               data_hrc = period_data - duty_data;
+       } else {
                /* calculate data_hrc */
-               data_hrc = duty_data;   
+               data_hrc = duty_data;
        }
        data_lrc = period_data;
 
        /* set hrc */
-       reg_addr = REG_PTC_RPTC_HRC(pwm->regs,dev->hwpwm);
+       reg_addr = REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm);
 #if PTC_DEBUG
-       printk("[starfive_pwm_ptc_config]reg_addr:0x%lx,HRC data:0x%x....\n",reg_addr,data_hrc);
+       dev_info(chip->dev, "[pwm_reg]reg_addr:0x%lx,HRC data:0x%x....\n",
+                reg_addr, data_hrc);
 #endif
        iowrite32(data_hrc, reg_addr);
 
-
        /* set lrc */
-       reg_addr = REG_PTC_RPTC_LRC(pwm->regs,dev->hwpwm);
+       reg_addr = REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm);
 #if PTC_DEBUG
-       printk("[starfive_pwm_ptc_config]reg_addr:0x%lx,LRC data:0x%x....\n",reg_addr,data_lrc);
-#endif 
-       iowrite32(data_lrc, reg_addr);  
+       dev_info(chip->dev, "[pwm_reg]reg_addr:0x%lx,LRC data:0x%x....\n",
+                reg_addr, data_lrc);
+#endif
+       iowrite32(data_lrc, reg_addr);
 
        /* set REG_RPTC_CNTR*/
        reg_addr = REG_PTC_RPTC_CNTR(pwm->regs, dev->hwpwm);
        iowrite32(0, reg_addr);
-       
+
        /* set REG_PTC_RPTC_CTRL*/
        reg_addr = REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm);
-       iowrite32(PTC_EN|PTC_OE, reg_addr);
-       
+       iowrite32(PTC_EN | PTC_OE, reg_addr);
+
        return 0;
 }
 
-
-
 static const struct pwm_ops starfive_pwm_ptc_ops = {
        .get_state      = starfive_pwm_ptc_get_state,
-       .apply          = (void*)starfive_pwm_ptc_apply,
+       .apply          = (void *)starfive_pwm_ptc_apply,
        .owner          = THIS_MODULE,
 };
 
-
-
-
 static int starfive_pwm_ptc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -212,10 +209,11 @@ static int starfive_pwm_ptc_probe(struct platform_device *pdev)
        struct starfive_pwm_ptc_device *pwm;
        struct pwm_chip *chip;
        struct resource *res;
+       unsigned long clk_tree_freq;
        int ret;
-       
+
 #if PTC_DEBUG
-       printk("starfive_pwm_ptc_probe in....\r\n");
+       dev_info(dev, "%s in....\r\n", __func__);
 #endif
        pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL);
        if (!pwm) {
@@ -227,50 +225,76 @@ static int starfive_pwm_ptc_probe(struct platform_device *pdev)
        chip->dev = dev;
        chip->ops = &starfive_pwm_ptc_ops;
 
-       /* how many parameters can be transfered to ptc,need to fix */
+       /* how many parameters can be transferred to ptc, need to fix */
        chip->of_pwm_n_cells = 3;
        chip->base = -1;
 
        /* get pwm channels count, max value is 8 */
        ret = of_property_read_u32(node, "starfive,npwm", &chip->npwm);
-       if (ret < 0 || chip->npwm > MAX_PWM) 
-       {
+       if (ret < 0 || chip->npwm > MAX_PWM)
                chip->npwm = MAX_PWM;
-       }
-#if PTC_DEBUG  
-       printk("[starfive_pwm_ptc_probe] npwm:0x%lx....\r\n",chip->npwm);
-#endif
-       /* get apb clock frequency */
-       ret = of_property_read_u32(node, "starfive,approx-period", &pwm->approx_period);
-
 #if PTC_DEBUG
-       printk("[starfive_pwm_ptc_probe] approx_period:%d....\r\n",pwm->approx_period);
+       dev_info(dev, "[%s] npwm:0x%lx....\r\n", __func__, chip->npwm);
 #endif
+
        /* get IO base address*/
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
 #if PTC_DEBUG
-       printk("[starfive_pwm_ptc_probe] res start:0x%lx,end:0x%lx....\r\n",res->start,res->end);
-#endif 
+       dev_info(dev, "[%s] res start:0x%lx,end:0x%lx....\r\n",
+                __func__, res->start, res->end);
+#endif
        pwm->regs = devm_ioremap_resource(dev, res);
-       if (IS_ERR(pwm->regs)) 
-       {
+       if (IS_ERR(pwm->regs)) {
                dev_err(dev, "Unable to map IO resources\n");
                return PTR_ERR(pwm->regs);
        }
-
 #if PTC_DEBUG
-       printk("[starfive_pwm_ptc_probe] regs:0x%lx....\r\n",pwm->regs);
+       dev_info(dev, "[%s] regs:0x%lx....\r\n", __func__, pwm->regs);
 #endif
 
+       /* get and enable clocks/resets */
        pwm->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(pwm->clk)) {
-               dev_err(dev, "Unable to find controller clock\n");
+               dev_err(dev, "Unable to get pwm clock\n");
                return PTR_ERR(pwm->clk);
        }
+       pwm->rst = devm_reset_control_get_exclusive(dev, NULL);
+       if (IS_ERR(pwm->rst)) {
+               dev_err(dev, "Unable to get pwm reset\n");
+               return PTR_ERR(pwm->rst);
+       }
 
-       /* after add,it will display as /sys/class/pwm/pwmchip0,0 is chip->base 
-        * after execute echo 0 > export in  , pwm0 can be seen */
+       ret = clk_prepare_enable(pwm->clk);
+       if (ret) {
+               dev_err(dev,
+                       "Failed to enable pwm clock, %d\n", ret);
+               return ret;
+       }
+       reset_control_deassert(pwm->rst);
+
+       /* get apb clock frequency */
+       ret = of_property_read_u32(node, "starfive,approx-period",
+                                  &pwm->approx_period);
+       if (ret)
+               pwm->approx_period = 2000000;
+#if PTC_DEBUG
+       dev_info(dev, "[%s] approx_period:%d....\r\n",
+                __func__, pwm->approx_period);
+#endif
+
+#ifndef HWBOARD_FPGA
+       clk_tree_freq = clk_get_rate(pwm->clk);
+       if (!clk_tree_freq)
+               dev_warn(dev,
+                       "get pwm apb clock rate failed.\n");
+       else
+               pwm->approx_period = (unsigned int)clk_tree_freq;
+#endif
+
+       /*
+        * after add, /sys/class/pwm/pwmchip0/ will appear,'0' is chip->base
+        * if execute 'echo 0 > export' in this directory, pwm0/ can be seen
+        */
        ret = pwmchip_add(chip);
        if (ret < 0) {
                dev_err(dev, "cannot register PTC: %d\n", ret);
@@ -278,9 +302,10 @@ static int starfive_pwm_ptc_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, pwm);
-       
+
 #if PTC_DEBUG
-       printk("starfive PWM PTC chip registered %d PWMs\n", chip->npwm);
+       dev_info(dev, "starfive PWM PTC chip registered %d PWMs\n",
+                chip->npwm);
 #endif
 
        return 0;
@@ -291,6 +316,7 @@ static int starfive_pwm_ptc_remove(struct platform_device *dev)
        struct starfive_pwm_ptc_device *pwm = platform_get_drvdata(dev);
        struct pwm_chip *chip = &pwm->chip;
 
+       clk_disable_unprepare(pwm->clk);
        pwmchip_remove(chip);
 
        return 0;
@@ -312,6 +338,5 @@ static struct platform_driver starfive_pwm_ptc_driver = {
 };
 module_platform_driver(starfive_pwm_ptc_driver);
 
-MODULE_DESCRIPTION("starfive PWM PTC driver");
+MODULE_DESCRIPTION("StarFive PWM PTC driver");
 MODULE_LICENSE("GPL v2");
-