Skip to content

Commit 3d593b6

Browse files
fabiobaltierithierryreding
authored andcommitted
pwm: pwm-cros-ec: Add channel type support
Add support for EC_PWM_TYPE_DISPLAY_LIGHT and EC_PWM_TYPE_KB_LIGHT pwm types to the PWM cros_ec_pwm driver. This allows specifying one of these PWM channel by functionality, and let the EC firmware pick the correct channel, thus abstracting the hardware implementation from the kernel driver. To use it, define the node with the "google,cros-ec-pwm-type" compatible. Signed-off-by: Fabio Baltieri <fabiobaltieri@chromium.org> Reviewed-by: Tzung-Bi Shih <tzungbi@kernel.org> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
1 parent a48d66d commit 3d593b6

File tree

1 file changed

+67
-15
lines changed

1 file changed

+67
-15
lines changed

drivers/pwm/pwm-cros-ec.c

Lines changed: 67 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,21 @@
1212
#include <linux/pwm.h>
1313
#include <linux/slab.h>
1414

15+
#include <dt-bindings/mfd/cros_ec.h>
16+
1517
/**
1618
* struct cros_ec_pwm_device - Driver data for EC PWM
1719
*
1820
* @dev: Device node
1921
* @ec: Pointer to EC device
2022
* @chip: PWM controller chip
23+
* @use_pwm_type: Use PWM types instead of generic channels
2124
*/
2225
struct cros_ec_pwm_device {
2326
struct device *dev;
2427
struct cros_ec_device *ec;
2528
struct pwm_chip chip;
29+
bool use_pwm_type;
2630
};
2731

2832
/**
@@ -58,14 +62,31 @@ static void cros_ec_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
5862
kfree(channel);
5963
}
6064

61-
static int cros_ec_pwm_set_duty(struct cros_ec_device *ec, u8 index, u16 duty)
65+
static int cros_ec_dt_type_to_pwm_type(u8 dt_index, u8 *pwm_type)
6266
{
67+
switch (dt_index) {
68+
case CROS_EC_PWM_DT_KB_LIGHT:
69+
*pwm_type = EC_PWM_TYPE_KB_LIGHT;
70+
return 0;
71+
case CROS_EC_PWM_DT_DISPLAY_LIGHT:
72+
*pwm_type = EC_PWM_TYPE_DISPLAY_LIGHT;
73+
return 0;
74+
default:
75+
return -EINVAL;
76+
}
77+
}
78+
79+
static int cros_ec_pwm_set_duty(struct cros_ec_pwm_device *ec_pwm, u8 index,
80+
u16 duty)
81+
{
82+
struct cros_ec_device *ec = ec_pwm->ec;
6383
struct {
6484
struct cros_ec_command msg;
6585
struct ec_params_pwm_set_duty params;
6686
} __packed buf;
6787
struct ec_params_pwm_set_duty *params = &buf.params;
6888
struct cros_ec_command *msg = &buf.msg;
89+
int ret;
6990

7091
memset(&buf, 0, sizeof(buf));
7192

@@ -75,14 +96,25 @@ static int cros_ec_pwm_set_duty(struct cros_ec_device *ec, u8 index, u16 duty)
7596
msg->outsize = sizeof(*params);
7697

7798
params->duty = duty;
78-
params->pwm_type = EC_PWM_TYPE_GENERIC;
79-
params->index = index;
99+
100+
if (ec_pwm->use_pwm_type) {
101+
ret = cros_ec_dt_type_to_pwm_type(index, &params->pwm_type);
102+
if (ret) {
103+
dev_err(ec->dev, "Invalid PWM type index: %d\n", index);
104+
return ret;
105+
}
106+
params->index = 0;
107+
} else {
108+
params->pwm_type = EC_PWM_TYPE_GENERIC;
109+
params->index = index;
110+
}
80111

81112
return cros_ec_cmd_xfer_status(ec, msg);
82113
}
83114

84-
static int cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index)
115+
static int cros_ec_pwm_get_duty(struct cros_ec_pwm_device *ec_pwm, u8 index)
85116
{
117+
struct cros_ec_device *ec = ec_pwm->ec;
86118
struct {
87119
struct cros_ec_command msg;
88120
union {
@@ -102,8 +134,17 @@ static int cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index)
102134
msg->insize = sizeof(*resp);
103135
msg->outsize = sizeof(*params);
104136

105-
params->pwm_type = EC_PWM_TYPE_GENERIC;
106-
params->index = index;
137+
if (ec_pwm->use_pwm_type) {
138+
ret = cros_ec_dt_type_to_pwm_type(index, &params->pwm_type);
139+
if (ret) {
140+
dev_err(ec->dev, "Invalid PWM type index: %d\n", index);
141+
return ret;
142+
}
143+
params->index = 0;
144+
} else {
145+
params->pwm_type = EC_PWM_TYPE_GENERIC;
146+
params->index = index;
147+
}
107148

108149
ret = cros_ec_cmd_xfer_status(ec, msg);
109150
if (ret < 0)
@@ -133,7 +174,7 @@ static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
133174
*/
134175
duty_cycle = state->enabled ? state->duty_cycle : 0;
135176

136-
ret = cros_ec_pwm_set_duty(ec_pwm->ec, pwm->hwpwm, duty_cycle);
177+
ret = cros_ec_pwm_set_duty(ec_pwm, pwm->hwpwm, duty_cycle);
137178
if (ret < 0)
138179
return ret;
139180

@@ -149,7 +190,7 @@ static void cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
149190
struct cros_ec_pwm *channel = pwm_get_chip_data(pwm);
150191
int ret;
151192

152-
ret = cros_ec_pwm_get_duty(ec_pwm->ec, pwm->hwpwm);
193+
ret = cros_ec_pwm_get_duty(ec_pwm, pwm->hwpwm);
153194
if (ret < 0) {
154195
dev_err(chip->dev, "error getting initial duty: %d\n", ret);
155196
return;
@@ -204,13 +245,13 @@ static const struct pwm_ops cros_ec_pwm_ops = {
204245
* of PWMs it supports directly, so we have to read the pwm duty cycle for
205246
* subsequent channels until we get an error.
206247
*/
207-
static int cros_ec_num_pwms(struct cros_ec_device *ec)
248+
static int cros_ec_num_pwms(struct cros_ec_pwm_device *ec_pwm)
208249
{
209250
int i, ret;
210251

211252
/* The index field is only 8 bits */
212253
for (i = 0; i <= U8_MAX; i++) {
213-
ret = cros_ec_pwm_get_duty(ec, i);
254+
ret = cros_ec_pwm_get_duty(ec_pwm, i);
214255
/*
215256
* We look for SUCCESS, INVALID_COMMAND, or INVALID_PARAM
216257
* responses; everything else is treated as an error.
@@ -236,6 +277,7 @@ static int cros_ec_pwm_probe(struct platform_device *pdev)
236277
{
237278
struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
238279
struct device *dev = &pdev->dev;
280+
struct device_node *np = pdev->dev.of_node;
239281
struct cros_ec_pwm_device *ec_pwm;
240282
struct pwm_chip *chip;
241283
int ret;
@@ -251,17 +293,26 @@ static int cros_ec_pwm_probe(struct platform_device *pdev)
251293
chip = &ec_pwm->chip;
252294
ec_pwm->ec = ec;
253295

296+
if (of_device_is_compatible(np, "google,cros-ec-pwm-type"))
297+
ec_pwm->use_pwm_type = true;
298+
254299
/* PWM chip */
255300
chip->dev = dev;
256301
chip->ops = &cros_ec_pwm_ops;
257302
chip->of_xlate = cros_ec_pwm_xlate;
258303
chip->of_pwm_n_cells = 1;
259-
ret = cros_ec_num_pwms(ec);
260-
if (ret < 0) {
261-
dev_err(dev, "Couldn't find PWMs: %d\n", ret);
262-
return ret;
304+
305+
if (ec_pwm->use_pwm_type) {
306+
chip->npwm = CROS_EC_PWM_DT_COUNT;
307+
} else {
308+
ret = cros_ec_num_pwms(ec_pwm);
309+
if (ret < 0) {
310+
dev_err(dev, "Couldn't find PWMs: %d\n", ret);
311+
return ret;
312+
}
313+
chip->npwm = ret;
263314
}
264-
chip->npwm = ret;
315+
265316
dev_dbg(dev, "Probed %u PWMs\n", chip->npwm);
266317

267318
ret = pwmchip_add(chip);
@@ -288,6 +339,7 @@ static int cros_ec_pwm_remove(struct platform_device *dev)
288339
#ifdef CONFIG_OF
289340
static const struct of_device_id cros_ec_pwm_of_match[] = {
290341
{ .compatible = "google,cros-ec-pwm" },
342+
{ .compatible = "google,cros-ec-pwm-type" },
291343
{},
292344
};
293345
MODULE_DEVICE_TABLE(of, cros_ec_pwm_of_match);

0 commit comments

Comments
 (0)