Hi! > The Light Pulse Generator (LPG) is a PWM-block found in a wide range of > PMICs from Qualcomm. It can operate on fixed parameters or based on a > lookup-table, altering the duty cycle over time - which provides the > means for e.g. hardware assisted transitions of LED brightness. > > Signed-off-by: Bjorn Andersson > --- > > Changes since v5: > - Make sure to not used the state of the last channel in a group to determine > if the current sink should be active for all channels in the group. > - Replacement of unsigned -1 with UINT_MAX > - Work around potential overflow by using larger data types, instead of separate code paths > - Use cpu_to_l16() rather than hand rolling them > - Minor style cleanups > > drivers/leds/Kconfig | 9 + > drivers/leds/Makefile | 1 + > drivers/leds/leds-qcom-lpg.c | 1190 ++++++++++++++++++++++++++++++++++ > 3 files changed, 1200 insertions(+) > create mode 100644 drivers/leds/leds-qcom-lpg.c Let's put this into drivers/leds/rgb/. You may need to create it. > +static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern, > + size_t len, unsigned int *lo_idx, unsigned int *hi_idx) > +{ > + unsigned int idx; > + __le16 val; No need for __XX variants outside of headers meant for userspace. > +#define LPG_ENABLE_GLITCH_REMOVAL BIT(5) > + > +static void lpg_enable_glitch(struct lpg_channel *chan) > +{ > + struct lpg *lpg = chan->lpg; > + > + regmap_update_bits(lpg->map, chan->base + PWM_TYPE_CONFIG_REG, > + LPG_ENABLE_GLITCH_REMOVAL, 0); > +} > + > +static void lpg_disable_glitch(struct lpg_channel *chan) > +{ > + struct lpg *lpg = chan->lpg; > + > + regmap_update_bits(lpg->map, chan->base + PWM_TYPE_CONFIG_REG, > + LPG_ENABLE_GLITCH_REMOVAL, > + LPG_ENABLE_GLITCH_REMOVAL); > +} Helper functions for single register write is kind of overkill... > +static int lpg_blink_set(struct lpg_led *led, > + unsigned long delay_on, unsigned long delay_off) > +{ > + struct lpg_channel *chan; > + unsigned int period_us; > + unsigned int duty_us; > + int i; > + > + if (!delay_on && !delay_off) { > + delay_on = 500; > + delay_off = 500; > + } Aren't you supposed to modify the values passed to you, so that userspace knows what the default rate is? > + ret = lpg_lut_store(lpg, pattern, len, &lo_idx, &hi_idx); > + if (ret < 0) > + goto out; Just do direct return. > +out: > + return ret; > +} > +static const struct pwm_ops lpg_pwm_ops = { > + .request = lpg_pwm_request, > + .apply = lpg_pwm_apply, > + .owner = THIS_MODULE, > +}; > + > +static int lpg_add_pwm(struct lpg *lpg) > +{ > + int ret; > + > + lpg->pwm.base = -1; > + lpg->pwm.dev = lpg->dev; > + lpg->pwm.npwm = lpg->num_channels; > + lpg->pwm.ops = &lpg_pwm_ops; > + > + ret = pwmchip_add(&lpg->pwm); > + if (ret) > + dev_err(lpg->dev, "failed to add PWM chip: ret %d\n", ret); > + > + return ret; > +} Do we need to do this? I'd rather have LED driver, than LED+PWM driver... Best regards, Pavel -- http://www.livejournal.com/~pavelmachek