hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/drivers/pwm/pwm-crc.c
....@@ -1,14 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (C) 2015 Intel Corporation. All rights reserved.
3
- *
4
- * This program is free software; you can redistribute it and/or
5
- * modify it under the terms of the GNU General Public License version
6
- * 2 as published by the Free Software Foundation.
7
- *
8
- * This program is distributed in the hope that it will be useful,
9
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
- * GNU General Public License for more details.
124 *
135 * Author: Shobhit Kumar <shobhit.kumar@intel.com>
146 */
....@@ -29,8 +21,8 @@
2921
3022 #define PWM_MAX_LEVEL 0xFF
3123
32
-#define PWM_BASE_CLK 6000000 /* 6 MHz */
33
-#define PWM_MAX_PERIOD_NS 21333 /* 46.875KHz */
24
+#define PWM_BASE_CLK_MHZ 6 /* 6 MHz */
25
+#define PWM_MAX_PERIOD_NS 5461334 /* 183 Hz */
3426
3527 /**
3628 * struct crystalcove_pwm - Crystal Cove PWM controller
....@@ -47,59 +39,121 @@
4739 return container_of(pc, struct crystalcove_pwm, chip);
4840 }
4941
50
-static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm)
42
+static int crc_pwm_calc_clk_div(int period_ns)
5143 {
52
- struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
44
+ int clk_div;
5345
54
- regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
46
+ clk_div = PWM_BASE_CLK_MHZ * period_ns / (256 * NSEC_PER_USEC);
47
+ /* clk_div 1 - 128, maps to register values 0-127 */
48
+ if (clk_div > 0)
49
+ clk_div--;
5550
56
- return 0;
51
+ return clk_div;
5752 }
5853
59
-static void crc_pwm_disable(struct pwm_chip *c, struct pwm_device *pwm)
54
+static int crc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
55
+ const struct pwm_state *state)
6056 {
61
- struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
62
-
63
- regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
64
-}
65
-
66
-static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm,
67
- int duty_ns, int period_ns)
68
-{
69
- struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
57
+ struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
7058 struct device *dev = crc_pwm->chip.dev;
71
- int level;
59
+ int err;
7260
73
- if (period_ns > PWM_MAX_PERIOD_NS) {
61
+ if (state->period > PWM_MAX_PERIOD_NS) {
7462 dev_err(dev, "un-supported period_ns\n");
7563 return -EINVAL;
7664 }
7765
78
- if (pwm_get_period(pwm) != period_ns) {
79
- int clk_div;
66
+ if (state->polarity != PWM_POLARITY_NORMAL)
67
+ return -EOPNOTSUPP;
8068
81
- /* changing the clk divisor, need to disable fisrt */
82
- crc_pwm_disable(c, pwm);
83
- clk_div = PWM_BASE_CLK * period_ns / NSEC_PER_SEC;
84
-
85
- regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
86
- clk_div | PWM_OUTPUT_ENABLE);
87
-
88
- /* enable back */
89
- crc_pwm_enable(c, pwm);
69
+ if (pwm_is_enabled(pwm) && !state->enabled) {
70
+ err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
71
+ if (err) {
72
+ dev_err(dev, "Error writing BACKLIGHT_EN %d\n", err);
73
+ return err;
74
+ }
9075 }
9176
92
- /* change the pwm duty cycle */
93
- level = duty_ns * PWM_MAX_LEVEL / period_ns;
94
- regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level);
77
+ if (pwm_get_duty_cycle(pwm) != state->duty_cycle ||
78
+ pwm_get_period(pwm) != state->period) {
79
+ u64 level = state->duty_cycle * PWM_MAX_LEVEL;
80
+
81
+ do_div(level, state->period);
82
+
83
+ err = regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level);
84
+ if (err) {
85
+ dev_err(dev, "Error writing PWM0_DUTY_CYCLE %d\n", err);
86
+ return err;
87
+ }
88
+ }
89
+
90
+ if (pwm_is_enabled(pwm) && state->enabled &&
91
+ pwm_get_period(pwm) != state->period) {
92
+ /* changing the clk divisor, clear PWM_OUTPUT_ENABLE first */
93
+ err = regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, 0);
94
+ if (err) {
95
+ dev_err(dev, "Error writing PWM0_CLK_DIV %d\n", err);
96
+ return err;
97
+ }
98
+ }
99
+
100
+ if (pwm_get_period(pwm) != state->period ||
101
+ pwm_is_enabled(pwm) != state->enabled) {
102
+ int clk_div = crc_pwm_calc_clk_div(state->period);
103
+ int pwm_output_enable = state->enabled ? PWM_OUTPUT_ENABLE : 0;
104
+
105
+ err = regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
106
+ clk_div | pwm_output_enable);
107
+ if (err) {
108
+ dev_err(dev, "Error writing PWM0_CLK_DIV %d\n", err);
109
+ return err;
110
+ }
111
+ }
112
+
113
+ if (!pwm_is_enabled(pwm) && state->enabled) {
114
+ err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
115
+ if (err) {
116
+ dev_err(dev, "Error writing BACKLIGHT_EN %d\n", err);
117
+ return err;
118
+ }
119
+ }
95120
96121 return 0;
97122 }
98123
124
+static void crc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
125
+ struct pwm_state *state)
126
+{
127
+ struct crystalcove_pwm *crc_pwm = to_crc_pwm(chip);
128
+ struct device *dev = crc_pwm->chip.dev;
129
+ unsigned int clk_div, clk_div_reg, duty_cycle_reg;
130
+ int error;
131
+
132
+ error = regmap_read(crc_pwm->regmap, PWM0_CLK_DIV, &clk_div_reg);
133
+ if (error) {
134
+ dev_err(dev, "Error reading PWM0_CLK_DIV %d\n", error);
135
+ return;
136
+ }
137
+
138
+ error = regmap_read(crc_pwm->regmap, PWM0_DUTY_CYCLE, &duty_cycle_reg);
139
+ if (error) {
140
+ dev_err(dev, "Error reading PWM0_DUTY_CYCLE %d\n", error);
141
+ return;
142
+ }
143
+
144
+ clk_div = (clk_div_reg & ~PWM_OUTPUT_ENABLE) + 1;
145
+
146
+ state->period =
147
+ DIV_ROUND_UP(clk_div * NSEC_PER_USEC * 256, PWM_BASE_CLK_MHZ);
148
+ state->duty_cycle =
149
+ DIV_ROUND_UP_ULL(duty_cycle_reg * state->period, PWM_MAX_LEVEL);
150
+ state->polarity = PWM_POLARITY_NORMAL;
151
+ state->enabled = !!(clk_div_reg & PWM_OUTPUT_ENABLE);
152
+}
153
+
99154 static const struct pwm_ops crc_pwm_ops = {
100
- .config = crc_pwm_config,
101
- .enable = crc_pwm_enable,
102
- .disable = crc_pwm_disable,
155
+ .apply = crc_pwm_apply,
156
+ .get_state = crc_pwm_get_state,
103157 };
104158
105159 static int crystalcove_pwm_probe(struct platform_device *pdev)