1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * The Netronix embedded controller is a microcontroller found in some 4 * e-book readers designed by the original design manufacturer Netronix, Inc. 5 * It contains RTC, battery monitoring, system power management, and PWM 6 * functionality. 7 * 8 * This driver implements PWM output. 9 * 10 * Copyright 2020 Jonathan Neuschäfer <j.neuschaefer@gmx.net> 11 * 12 * Limitations: 13 * - The get_state callback is not implemented, because the current state of 14 * the PWM output can't be read back from the hardware. 15 * - The hardware can only generate normal polarity output. 16 * - The period and duty cycle can't be changed together in one atomic action. 17 */ 18 19 #include <linux/mfd/ntxec.h> 20 #include <linux/module.h> 21 #include <linux/platform_device.h> 22 #include <linux/pwm.h> 23 #include <linux/regmap.h> 24 #include <linux/types.h> 25 26 struct ntxec_pwm { 27 struct ntxec *ec; 28 struct pwm_chip chip; 29 }; 30 31 static struct ntxec_pwm *ntxec_pwm_from_chip(struct pwm_chip *chip) 32 { 33 return container_of(chip, struct ntxec_pwm, chip); 34 } 35 36 #define NTXEC_REG_AUTO_OFF_HI 0xa1 37 #define NTXEC_REG_AUTO_OFF_LO 0xa2 38 #define NTXEC_REG_ENABLE 0xa3 39 #define NTXEC_REG_PERIOD_LOW 0xa4 40 #define NTXEC_REG_PERIOD_HIGH 0xa5 41 #define NTXEC_REG_DUTY_LOW 0xa6 42 #define NTXEC_REG_DUTY_HIGH 0xa7 43 44 /* 45 * The time base used in the EC is 8MHz, or 125ns. Period and duty cycle are 46 * measured in this unit. 47 */ 48 #define TIME_BASE_NS 125 49 50 /* 51 * The maximum input value (in nanoseconds) is determined by the time base and 52 * the range of the hardware registers that hold the converted value. 53 * It fits into 32 bits, so we can do our calculations in 32 bits as well. 54 */ 55 #define MAX_PERIOD_NS (TIME_BASE_NS * 0xffff) 56 57 static int ntxec_pwm_set_raw_period_and_duty_cycle(struct pwm_chip *chip, 58 int period, int duty) 59 { 60 struct ntxec_pwm *priv = ntxec_pwm_from_chip(chip); 61 62 /* 63 * Changes to the period and duty cycle take effect as soon as the 64 * corresponding low byte is written, so the hardware may be configured 65 * to an inconsistent state after the period is written and before the 66 * duty cycle is fully written. If, in such a case, the old duty cycle 67 * is longer than the new period, the EC may output 100% for a moment. 68 * 69 * To minimize the time between the changes to period and duty cycle 70 * taking effect, the writes are interleaved. 71 */ 72 73 struct reg_sequence regs[] = { 74 { NTXEC_REG_PERIOD_HIGH, ntxec_reg8(period >> 8) }, 75 { NTXEC_REG_DUTY_HIGH, ntxec_reg8(duty >> 8) }, 76 { NTXEC_REG_PERIOD_LOW, ntxec_reg8(period) }, 77 { NTXEC_REG_DUTY_LOW, ntxec_reg8(duty) }, 78 }; 79 80 return regmap_multi_reg_write(priv->ec->regmap, regs, ARRAY_SIZE(regs)); 81 } 82 83 static int ntxec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm_dev, 84 const struct pwm_state *state) 85 { 86 struct ntxec_pwm *priv = ntxec_pwm_from_chip(chip); 87 unsigned int period, duty; 88 int res; 89 90 if (state->polarity != PWM_POLARITY_NORMAL) 91 return -EINVAL; 92 93 period = min_t(u64, state->period, MAX_PERIOD_NS); 94 duty = min_t(u64, state->duty_cycle, period); 95 96 period /= TIME_BASE_NS; 97 duty /= TIME_BASE_NS; 98 99 /* 100 * Writing a duty cycle of zero puts the device into a state where 101 * writing a higher duty cycle doesn't result in the brightness that it 102 * usually results in. This can be fixed by cycling the ENABLE register. 103 * 104 * As a workaround, write ENABLE=0 when the duty cycle is zero. 105 * The case that something has previously set the duty cycle to zero 106 * but ENABLE=1, is not handled. 107 */ 108 if (state->enabled && duty != 0) { 109 res = ntxec_pwm_set_raw_period_and_duty_cycle(chip, period, duty); 110 if (res) 111 return res; 112 113 res = regmap_write(priv->ec->regmap, NTXEC_REG_ENABLE, ntxec_reg8(1)); 114 if (res) 115 return res; 116 117 /* Disable the auto-off timer */ 118 res = regmap_write(priv->ec->regmap, NTXEC_REG_AUTO_OFF_HI, ntxec_reg8(0xff)); 119 if (res) 120 return res; 121 122 return regmap_write(priv->ec->regmap, NTXEC_REG_AUTO_OFF_LO, ntxec_reg8(0xff)); 123 } else { 124 return regmap_write(priv->ec->regmap, NTXEC_REG_ENABLE, ntxec_reg8(0)); 125 } 126 } 127 128 static const struct pwm_ops ntxec_pwm_ops = { 129 .apply = ntxec_pwm_apply, 130 /* 131 * No .get_state callback, because the current state cannot be read 132 * back from the hardware. 133 */ 134 }; 135 136 static int ntxec_pwm_probe(struct platform_device *pdev) 137 { 138 struct ntxec *ec = dev_get_drvdata(pdev->dev.parent); 139 struct ntxec_pwm *priv; 140 struct pwm_chip *chip; 141 142 device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); 143 144 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 145 if (!priv) 146 return -ENOMEM; 147 148 priv->ec = ec; 149 150 chip = &priv->chip; 151 chip->dev = &pdev->dev; 152 chip->ops = &ntxec_pwm_ops; 153 chip->npwm = 1; 154 155 return devm_pwmchip_add(&pdev->dev, chip); 156 } 157 158 static struct platform_driver ntxec_pwm_driver = { 159 .driver = { 160 .name = "ntxec-pwm", 161 }, 162 .probe = ntxec_pwm_probe, 163 }; 164 module_platform_driver(ntxec_pwm_driver); 165 166 MODULE_AUTHOR("Jonathan Neuschäfer <j.neuschaefer@gmx.net>"); 167 MODULE_DESCRIPTION("PWM driver for Netronix EC"); 168 MODULE_LICENSE("GPL"); 169 MODULE_ALIAS("platform:ntxec-pwm"); 170