• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * pwm_hi35xx_linux.c
3  *
4  * pwm driver of hi35xx
5  *
6  * Copyright (c) 2020-2023 Huawei Device Co., Ltd.
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  */
18 
19 #include "pwm_hi35xx.h"
20 #include <linux/clk.h>
21 #include <linux/module.h>
22 #include <linux/of_platform.h>
23 #include <linux/pwm.h>
24 #include <linux/version.h>
25 #include "hdf_log.h"
26 
27 #define HDF_LOG_TAG pwm_hi35xx_linux
28 #define PWM_ENABLE_MASK 0x1
29 #define PWM_HI35XX_N_CELLS 2
30 
31 struct Hi35xxPwmChip {
32     struct pwm_chip chip;
33     struct HiPwmRegs *reg;
34     void __iomem *base;
35     struct clk *clk;
36 };
37 
38 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
Hi35xxPwmApply(struct pwm_chip * chip,struct pwm_device * pwm,const struct pwm_state * state)39 static int Hi35xxPwmApply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state)
40 #else
41 static int Hi35xxPwmApply(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state)
42 #endif
43 {
44     struct HiPwmRegs *reg = NULL;
45     struct Hi35xxPwmChip *hi35xxChip = (struct Hi35xxPwmChip *)chip;
46 
47     if (hi35xxChip == NULL || pwm == NULL || state == NULL) {
48         HDF_LOGE("Hi35xxPwmApply: parameter is null!\n");
49         return -EINVAL;
50     }
51     reg = (struct HiPwmRegs *)hi35xxChip->base;
52     if (state->polarity != PWM_POLARITY_NORMAL && state->polarity != PWM_POLARITY_INVERSED) {
53         HDF_LOGE("Hi35xxPwmApply: polarity %u is invalid!", state->polarity);
54         return -EINVAL;
55     }
56 
57     if (state->period < PWM_MIN_PERIOD) {
58         HDF_LOGE("Hi35xxPwmApply: period %llu is not support, min period %d!", state->period, PWM_MIN_PERIOD);
59         return -EINVAL;
60     }
61     if (state->duty_cycle < 1 || state->duty_cycle > state->period) {
62         HDF_LOGE("Hi35xxPwmApply: duty %llu is not support, duty must in [1, period = %llu]!",
63             state->duty_cycle, state->period);
64         return -EINVAL;
65     }
66 
67     HiPwmDisable(reg);
68     HDF_LOGI("Hi35xxPwmApply: [HiPwmDisable] done!");
69     if (pwm->state.polarity != state->polarity) {
70         HiPwmSetPolarity(reg, state->polarity);
71         HDF_LOGI("Hi35xxPwmApply: [HiPwmSetPolarity] done, polarity: %u -> %u!", pwm->state.polarity, state->polarity);
72     }
73     if (pwm->state.period != state->period) {
74         HiPwmSetPeriod(reg, state->period);
75         HDF_LOGI("Hi35xxPwmApply: [HiPwmSetPeriod] done, period: %llu -> %llu!", pwm->state.period, state->period);
76     }
77     if (pwm->state.duty_cycle != state->duty_cycle) {
78         HiPwmSetDuty(reg, state->duty_cycle);
79         HDF_LOGI("Hi35xxPwmApply: [HiPwmSetDuty] done, duty: %llu -> %llu!", pwm->state.duty_cycle, state->duty_cycle);
80     }
81     if (state->enabled) {
82         HiPwmAlwaysOutput(reg);
83         HDF_LOGI("Hi35xxPwmApply: [HiPwmAlwaysOutput] done, then enable!");
84     }
85 
86     HDF_LOGI("Hi35xxPwmApply: set PwmConfig done: number none, period %llu, duty %llu, polarity %u, enable %u!",
87         state->period, state->duty_cycle, state->polarity, state->enabled);
88     HDF_LOGI("Hi35xxPwmApply: success!");
89 
90     return 0;
91 }
92 
Hi35xxGetState(struct pwm_chip * chip,struct pwm_device * pwm,struct pwm_state * state)93 static void Hi35xxGetState(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state)
94 {
95     struct HiPwmRegs *reg = NULL;
96     struct Hi35xxPwmChip *hi35xxChip = (struct Hi35xxPwmChip *)chip;
97 
98     if (hi35xxChip == NULL || pwm == NULL || state == NULL) {
99         HDF_LOGE("Hi35xxGetState: parameter is null!\n");
100         return;
101     }
102     reg = (struct HiPwmRegs *)hi35xxChip->base;
103     state->period = reg->cfg0 * PWM_CLK_PERIOD;
104     state->duty_cycle = reg->cfg1 * PWM_CLK_PERIOD;
105     state->polarity = (reg->ctrl & (1 << PWM_INV_OFFSET)) >> PWM_INV_OFFSET;
106     state->enabled = reg->ctrl & PWM_ENABLE_MASK;
107 
108     HDF_LOGI("Hi35xxGetState: get PwmConfig: number none, period %llu, duty %llu, polarity %u, enable %u!",
109         state->period, state->duty_cycle, state->polarity, state->enabled);
110 }
111 
112 static struct pwm_ops Hi35xxPwmOps = {
113     .apply = Hi35xxPwmApply,
114     .get_state = Hi35xxGetState,
115     .owner = THIS_MODULE,
116 };
117 
PwmProbe(struct platform_device * pdev)118 static int PwmProbe(struct platform_device *pdev)
119 {
120     int ret;
121     struct resource *r = NULL;
122     struct Hi35xxPwmChip *chip = NULL;
123     struct device_node *np = pdev->dev.of_node;
124 
125     if (!np) {
126         dev_err(&pdev->dev, "invalid devicetree node\n");
127         return -EINVAL;
128     }
129 
130     chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
131     if (chip == NULL) {
132         return -ENOMEM;
133     }
134     chip->chip.dev = &pdev->dev;
135     chip->chip.ops = &Hi35xxPwmOps;
136     chip->chip.of_xlate = NULL;
137     chip->chip.of_pwm_n_cells = PWM_HI35XX_N_CELLS;
138     chip->chip.base = -1;
139     chip->chip.npwm = 1;
140     r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
141     chip->base = devm_ioremap_resource(&pdev->dev, r);
142     if (IS_ERR(chip->base)) {
143         devm_kfree(&pdev->dev, chip);
144         return PTR_ERR(chip->base);
145     }
146     chip->reg = (struct HiPwmRegs *)chip->base;
147     chip->clk = devm_clk_get(&pdev->dev, NULL);
148     if (IS_ERR(chip->clk)) {
149         dev_err(&pdev->dev, "failed to get clock\n");
150         devm_kfree(&pdev->dev, chip);
151         return PTR_ERR(chip->clk);
152     }
153     ret = clk_prepare_enable(chip->clk);
154     if (ret < 0) {
155         dev_err(&pdev->dev, "failed to enable clock\n");
156         devm_kfree(&pdev->dev, chip);
157         return ret;
158     }
159     ret = pwmchip_add(&chip->chip);
160     if (ret < 0) {
161         dev_err(&pdev->dev, "failed to add PWM chip\n");
162         devm_kfree(&pdev->dev, chip);
163         return ret;
164     }
165 
166     platform_set_drvdata(pdev, chip);
167     return ret;
168 }
169 
PwmRemove(struct platform_device * pdev)170 static int PwmRemove(struct platform_device *pdev)
171 {
172     int ret;
173     struct Hi35xxPwmChip *chip = NULL;
174 
175     chip = platform_get_drvdata(pdev);
176     if (chip == NULL) {
177         HDF_LOGE("PwmRemove: chip is null!\n");
178         return -ENODEV;
179     }
180     ret = pwmchip_remove(&chip->chip);
181     if (ret < 0) {
182         return ret;
183     }
184     clk_disable_unprepare(chip->clk);
185     return 0;
186 }
187 
188 static const struct of_device_id g_pwmMatch[] = {
189     { .compatible = "hisilicon,pwm" },
190     {},
191 };
192 
193 static struct platform_driver g_pwmDriver = {
194     .probe = PwmProbe,
195     .remove = PwmRemove,
196     .driver = {
197         .name = "pwm",
198         .of_match_table = g_pwmMatch,
199     }
200 };
201 module_platform_driver(g_pwmDriver);
202 MODULE_LICENSE("GPL");
203