0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/platform_data/cros_ec_commands.h>
0010 #include <linux/platform_data/cros_ec_proto.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/pwm.h>
0013 #include <linux/slab.h>
0014
0015 #include <dt-bindings/mfd/cros_ec.h>
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 struct cros_ec_pwm_device {
0026 struct device *dev;
0027 struct cros_ec_device *ec;
0028 struct pwm_chip chip;
0029 bool use_pwm_type;
0030 };
0031
0032
0033
0034
0035
0036 struct cros_ec_pwm {
0037 u16 duty_cycle;
0038 };
0039
0040 static inline struct cros_ec_pwm_device *pwm_to_cros_ec_pwm(struct pwm_chip *c)
0041 {
0042 return container_of(c, struct cros_ec_pwm_device, chip);
0043 }
0044
0045 static int cros_ec_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
0046 {
0047 struct cros_ec_pwm *channel;
0048
0049 channel = kzalloc(sizeof(*channel), GFP_KERNEL);
0050 if (!channel)
0051 return -ENOMEM;
0052
0053 pwm_set_chip_data(pwm, channel);
0054
0055 return 0;
0056 }
0057
0058 static void cros_ec_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
0059 {
0060 struct cros_ec_pwm *channel = pwm_get_chip_data(pwm);
0061
0062 kfree(channel);
0063 }
0064
0065 static int cros_ec_dt_type_to_pwm_type(u8 dt_index, u8 *pwm_type)
0066 {
0067 switch (dt_index) {
0068 case CROS_EC_PWM_DT_KB_LIGHT:
0069 *pwm_type = EC_PWM_TYPE_KB_LIGHT;
0070 return 0;
0071 case CROS_EC_PWM_DT_DISPLAY_LIGHT:
0072 *pwm_type = EC_PWM_TYPE_DISPLAY_LIGHT;
0073 return 0;
0074 default:
0075 return -EINVAL;
0076 }
0077 }
0078
0079 static int cros_ec_pwm_set_duty(struct cros_ec_pwm_device *ec_pwm, u8 index,
0080 u16 duty)
0081 {
0082 struct cros_ec_device *ec = ec_pwm->ec;
0083 struct {
0084 struct cros_ec_command msg;
0085 struct ec_params_pwm_set_duty params;
0086 } __packed buf;
0087 struct ec_params_pwm_set_duty *params = &buf.params;
0088 struct cros_ec_command *msg = &buf.msg;
0089 int ret;
0090
0091 memset(&buf, 0, sizeof(buf));
0092
0093 msg->version = 0;
0094 msg->command = EC_CMD_PWM_SET_DUTY;
0095 msg->insize = 0;
0096 msg->outsize = sizeof(*params);
0097
0098 params->duty = duty;
0099
0100 if (ec_pwm->use_pwm_type) {
0101 ret = cros_ec_dt_type_to_pwm_type(index, ¶ms->pwm_type);
0102 if (ret) {
0103 dev_err(ec->dev, "Invalid PWM type index: %d\n", index);
0104 return ret;
0105 }
0106 params->index = 0;
0107 } else {
0108 params->pwm_type = EC_PWM_TYPE_GENERIC;
0109 params->index = index;
0110 }
0111
0112 return cros_ec_cmd_xfer_status(ec, msg);
0113 }
0114
0115 static int cros_ec_pwm_get_duty(struct cros_ec_pwm_device *ec_pwm, u8 index)
0116 {
0117 struct cros_ec_device *ec = ec_pwm->ec;
0118 struct {
0119 struct cros_ec_command msg;
0120 union {
0121 struct ec_params_pwm_get_duty params;
0122 struct ec_response_pwm_get_duty resp;
0123 };
0124 } __packed buf;
0125 struct ec_params_pwm_get_duty *params = &buf.params;
0126 struct ec_response_pwm_get_duty *resp = &buf.resp;
0127 struct cros_ec_command *msg = &buf.msg;
0128 int ret;
0129
0130 memset(&buf, 0, sizeof(buf));
0131
0132 msg->version = 0;
0133 msg->command = EC_CMD_PWM_GET_DUTY;
0134 msg->insize = sizeof(*resp);
0135 msg->outsize = sizeof(*params);
0136
0137 if (ec_pwm->use_pwm_type) {
0138 ret = cros_ec_dt_type_to_pwm_type(index, ¶ms->pwm_type);
0139 if (ret) {
0140 dev_err(ec->dev, "Invalid PWM type index: %d\n", index);
0141 return ret;
0142 }
0143 params->index = 0;
0144 } else {
0145 params->pwm_type = EC_PWM_TYPE_GENERIC;
0146 params->index = index;
0147 }
0148
0149 ret = cros_ec_cmd_xfer_status(ec, msg);
0150 if (ret < 0)
0151 return ret;
0152
0153 return resp->duty;
0154 }
0155
0156 static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
0157 const struct pwm_state *state)
0158 {
0159 struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip);
0160 struct cros_ec_pwm *channel = pwm_get_chip_data(pwm);
0161 u16 duty_cycle;
0162 int ret;
0163
0164
0165 if (state->period != EC_PWM_MAX_DUTY)
0166 return -EINVAL;
0167
0168 if (state->polarity != PWM_POLARITY_NORMAL)
0169 return -EINVAL;
0170
0171
0172
0173
0174
0175 duty_cycle = state->enabled ? state->duty_cycle : 0;
0176
0177 ret = cros_ec_pwm_set_duty(ec_pwm, pwm->hwpwm, duty_cycle);
0178 if (ret < 0)
0179 return ret;
0180
0181 channel->duty_cycle = state->duty_cycle;
0182
0183 return 0;
0184 }
0185
0186 static void cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
0187 struct pwm_state *state)
0188 {
0189 struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip);
0190 struct cros_ec_pwm *channel = pwm_get_chip_data(pwm);
0191 int ret;
0192
0193 ret = cros_ec_pwm_get_duty(ec_pwm, pwm->hwpwm);
0194 if (ret < 0) {
0195 dev_err(chip->dev, "error getting initial duty: %d\n", ret);
0196 return;
0197 }
0198
0199 state->enabled = (ret > 0);
0200 state->period = EC_PWM_MAX_DUTY;
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211 if (ret == 0 && channel->duty_cycle > 0)
0212 state->duty_cycle = channel->duty_cycle;
0213 else
0214 state->duty_cycle = ret;
0215 }
0216
0217 static struct pwm_device *
0218 cros_ec_pwm_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
0219 {
0220 struct pwm_device *pwm;
0221
0222 if (args->args[0] >= pc->npwm)
0223 return ERR_PTR(-EINVAL);
0224
0225 pwm = pwm_request_from_chip(pc, args->args[0], NULL);
0226 if (IS_ERR(pwm))
0227 return pwm;
0228
0229
0230 pwm->args.period = EC_PWM_MAX_DUTY;
0231
0232 return pwm;
0233 }
0234
0235 static const struct pwm_ops cros_ec_pwm_ops = {
0236 .request = cros_ec_pwm_request,
0237 .free = cros_ec_pwm_free,
0238 .get_state = cros_ec_pwm_get_state,
0239 .apply = cros_ec_pwm_apply,
0240 .owner = THIS_MODULE,
0241 };
0242
0243
0244
0245
0246
0247
0248 static int cros_ec_num_pwms(struct cros_ec_pwm_device *ec_pwm)
0249 {
0250 int i, ret;
0251
0252
0253 for (i = 0; i <= U8_MAX; i++) {
0254 ret = cros_ec_pwm_get_duty(ec_pwm, i);
0255
0256
0257
0258
0259
0260
0261 switch (ret) {
0262 case -EOPNOTSUPP:
0263 return -ENODEV;
0264 case -EINVAL:
0265 return i;
0266 default:
0267 if (ret < 0)
0268 return ret;
0269 break;
0270 }
0271 }
0272
0273 return U8_MAX;
0274 }
0275
0276 static int cros_ec_pwm_probe(struct platform_device *pdev)
0277 {
0278 struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
0279 struct device *dev = &pdev->dev;
0280 struct device_node *np = pdev->dev.of_node;
0281 struct cros_ec_pwm_device *ec_pwm;
0282 struct pwm_chip *chip;
0283 int ret;
0284
0285 if (!ec) {
0286 dev_err(dev, "no parent EC device\n");
0287 return -EINVAL;
0288 }
0289
0290 ec_pwm = devm_kzalloc(dev, sizeof(*ec_pwm), GFP_KERNEL);
0291 if (!ec_pwm)
0292 return -ENOMEM;
0293 chip = &ec_pwm->chip;
0294 ec_pwm->ec = ec;
0295
0296 if (of_device_is_compatible(np, "google,cros-ec-pwm-type"))
0297 ec_pwm->use_pwm_type = true;
0298
0299
0300 chip->dev = dev;
0301 chip->ops = &cros_ec_pwm_ops;
0302 chip->of_xlate = cros_ec_pwm_xlate;
0303 chip->of_pwm_n_cells = 1;
0304
0305 if (ec_pwm->use_pwm_type) {
0306 chip->npwm = CROS_EC_PWM_DT_COUNT;
0307 } else {
0308 ret = cros_ec_num_pwms(ec_pwm);
0309 if (ret < 0) {
0310 dev_err(dev, "Couldn't find PWMs: %d\n", ret);
0311 return ret;
0312 }
0313 chip->npwm = ret;
0314 }
0315
0316 dev_dbg(dev, "Probed %u PWMs\n", chip->npwm);
0317
0318 ret = pwmchip_add(chip);
0319 if (ret < 0) {
0320 dev_err(dev, "cannot register PWM: %d\n", ret);
0321 return ret;
0322 }
0323
0324 platform_set_drvdata(pdev, ec_pwm);
0325
0326 return ret;
0327 }
0328
0329 static int cros_ec_pwm_remove(struct platform_device *dev)
0330 {
0331 struct cros_ec_pwm_device *ec_pwm = platform_get_drvdata(dev);
0332 struct pwm_chip *chip = &ec_pwm->chip;
0333
0334 pwmchip_remove(chip);
0335
0336 return 0;
0337 }
0338
0339 #ifdef CONFIG_OF
0340 static const struct of_device_id cros_ec_pwm_of_match[] = {
0341 { .compatible = "google,cros-ec-pwm" },
0342 { .compatible = "google,cros-ec-pwm-type" },
0343 {},
0344 };
0345 MODULE_DEVICE_TABLE(of, cros_ec_pwm_of_match);
0346 #endif
0347
0348 static struct platform_driver cros_ec_pwm_driver = {
0349 .probe = cros_ec_pwm_probe,
0350 .remove = cros_ec_pwm_remove,
0351 .driver = {
0352 .name = "cros-ec-pwm",
0353 .of_match_table = of_match_ptr(cros_ec_pwm_of_match),
0354 },
0355 };
0356 module_platform_driver(cros_ec_pwm_driver);
0357
0358 MODULE_ALIAS("platform:cros-ec-pwm");
0359 MODULE_DESCRIPTION("ChromeOS EC PWM driver");
0360 MODULE_LICENSE("GPL v2");