Lines Matching +full:pwm +full:- +full:map +full:- +full:mask

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2017-2022 Linaro Ltd
4 * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
5 * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
9 #include <linux/led-class-multicolor.h>
11 #include <linux/nvmem-consumer.h>
14 #include <linux/pwm.h>
17 #include <linux/soc/qcom/qcom-pbs.h>
43 #define PWM_DTEST_REG(x) (0xe2 + (x) - 1)
87 * struct lpg - LPG device context
89 * @map: regmap for register access
90 * @lock: used to synchronize LED and pwm callback requests
91 * @pwm: PWM-chip object, if operating in PWM mode
101 * @triled_src: power-source for the TRILED
104 * @channels: list of PWM channels
109 struct regmap *map; member
113 struct pwm_chip *pwm; member
136 * struct lpg_channel - per channel data
138 * @base: base address of the PWM channel
139 * @triled_mask: mask in TRILED to enable this channel
140 * @lut_mask: mask in LUT to start pattern generator for this channel
153 * @pwm_resolution_sel: pwm resolution selector
202 * struct lpg_led - logical LED object
220 * struct lpg_channel_data - per channel initialization data
222 * @base: base address for PWM channel registers
232 * struct lpg_data - initialization data
258 if (!lpg->lpg_chan_sdam) in lpg_clear_pbs_trigger()
261 lpg->pbs_en_bitmap &= (~lut_mask); in lpg_clear_pbs_trigger()
262 if (!lpg->pbs_en_bitmap) { in lpg_clear_pbs_trigger()
263 rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_REG_PBS_SEQ_EN, 1, &val); in lpg_clear_pbs_trigger()
267 if (lpg->lut_sdam) { in lpg_clear_pbs_trigger()
269 rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_PBS_TRIG_CLR, 1, &val); in lpg_clear_pbs_trigger()
283 if (!lpg->lpg_chan_sdam) in lpg_set_pbs_trigger()
286 if (!lpg->pbs_en_bitmap) { in lpg_set_pbs_trigger()
287 rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_REG_PBS_SEQ_EN, 1, &val); in lpg_set_pbs_trigger()
291 if (lpg->lut_sdam) { in lpg_set_pbs_trigger()
292 rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_PBS_TRIG_SET, 1, &val); in lpg_set_pbs_trigger()
296 rc = qcom_pbs_trigger_event(lpg->pbs_dev, val); in lpg_set_pbs_trigger()
301 lpg->pbs_en_bitmap |= lut_mask; in lpg_set_pbs_trigger()
308 u32 addr = SDAM_LUT_EN_OFFSET + chan->sdam_offset; in lpg_sdam_configure_triggers()
310 if (!chan->lpg->lpg_chan_sdam) in lpg_sdam_configure_triggers()
313 return nvmem_device_write(chan->lpg->lpg_chan_sdam, addr, 1, &set_trig); in lpg_sdam_configure_triggers()
316 static int triled_set(struct lpg *lpg, unsigned int mask, unsigned int enable) in triled_set() argument
319 if (!lpg->triled_base) in triled_set()
322 return regmap_update_bits(lpg->map, lpg->triled_base + TRI_LED_EN_CTL, in triled_set()
323 mask, enable); in triled_set()
334 if (len > lpg->lut_size) { in lpg_lut_store_sdam()
335 dev_err(lpg->dev, "Pattern length (%zu) exceeds maximum pattern length (%d)\n", in lpg_lut_store_sdam()
336 len, lpg->lut_size); in lpg_lut_store_sdam()
337 return -EINVAL; in lpg_lut_store_sdam()
340 idx = bitmap_find_next_zero_area(lpg->lut_bitmap, lpg->lut_size, 0, len, 0); in lpg_lut_store_sdam()
341 if (idx >= lpg->lut_size) in lpg_lut_store_sdam()
342 return -ENOSPC; in lpg_lut_store_sdam()
347 if (lpg->lut_sdam) { in lpg_lut_store_sdam()
349 rc = nvmem_device_write(lpg->lut_sdam, addr, 1, &brightness); in lpg_lut_store_sdam()
352 rc = nvmem_device_write(lpg->lpg_chan_sdam, addr, 1, &brightness); in lpg_lut_store_sdam()
359 bitmap_set(lpg->lut_bitmap, idx, len); in lpg_lut_store_sdam()
362 *hi_idx = idx + len - 1; in lpg_lut_store_sdam()
374 idx = bitmap_find_next_zero_area(lpg->lut_bitmap, lpg->lut_size, in lpg_lut_store()
376 if (idx >= lpg->lut_size) in lpg_lut_store()
377 return -ENOMEM; in lpg_lut_store()
382 regmap_bulk_write(lpg->map, lpg->lut_base + LPG_LUT_REG(idx + i), in lpg_lut_store()
386 bitmap_set(lpg->lut_bitmap, idx, len); in lpg_lut_store()
389 *hi_idx = idx + len - 1; in lpg_lut_store()
398 len = hi_idx - lo_idx + 1; in lpg_lut_free()
402 bitmap_clear(lpg->lut_bitmap, lo_idx, len); in lpg_lut_free()
405 static int lpg_lut_sync(struct lpg *lpg, unsigned int mask) in lpg_lut_sync() argument
407 if (!lpg->lut_base) in lpg_lut_sync()
410 return regmap_write(lpg->map, lpg->lut_base + RAMP_CONTROL_REG, mask); in lpg_lut_sync()
434 * The PWM period is determined by: in lpg_calc_freq()
437 * period = -------------------------- in lpg_calc_freq()
440 * Resolution = 2^{6 or 9} bits for PWM or in lpg_calc_freq()
441 * 2^{8, 9, 10, 11, 12, 13, 14, 15} bits for high resolution PWM in lpg_calc_freq()
445 * This allows for periods between 3uS and 384s for PWM channels and periods between in lpg_calc_freq()
447 * The PWM framework wants a period of equal or lower length than requested, in lpg_calc_freq()
451 if (chan->subtype == LPG_SUBTYPE_HI_RES_PWM) { in lpg_calc_freq()
465 min_period = div64_u64((u64)NSEC_PER_SEC * ((1 << pwm_resolution_arr[0]) - 1), in lpg_calc_freq()
466 clk_rate_arr[clk_len - 1]); in lpg_calc_freq()
468 return -EINVAL; in lpg_calc_freq()
481 * M = log2 ------------------------------------- in lpg_calc_freq()
486 resolution = (1 << pwm_resolution_arr[i]) - 1; in lpg_calc_freq()
506 error = period - actual; in lpg_calc_freq()
518 chan->clk_sel = best_clk; in lpg_calc_freq()
519 chan->pre_div_sel = best_div; in lpg_calc_freq()
520 chan->pre_div_exp = best_m; in lpg_calc_freq()
521 chan->period = best_period; in lpg_calc_freq()
522 chan->pwm_resolution_sel = best_pwm_resolution_sel; in lpg_calc_freq()
532 if (chan->subtype == LPG_SUBTYPE_HI_RES_PWM) { in lpg_calc_duty()
533 max = BIT(lpg_pwm_resolution_hi_res[chan->pwm_resolution_sel]) - 1; in lpg_calc_duty()
534 clk_rate = lpg_clk_rates_hi_res[chan->clk_sel]; in lpg_calc_duty()
536 max = BIT(lpg_pwm_resolution[chan->pwm_resolution_sel]) - 1; in lpg_calc_duty()
537 clk_rate = lpg_clk_rates[chan->clk_sel]; in lpg_calc_duty()
541 (u64)NSEC_PER_SEC * lpg_pre_divs[chan->pre_div_sel] * (1 << chan->pre_div_exp)); in lpg_calc_duty()
543 chan->pwm_value = min(val, max); in lpg_calc_duty()
549 struct lpg *lpg = chan->lpg; in lpg_apply_freq()
551 if (!chan->enabled) in lpg_apply_freq()
554 val = chan->clk_sel; in lpg_apply_freq()
557 switch (chan->subtype) { in lpg_apply_freq()
562 val |= FIELD_PREP(PWM_SIZE_SELECT_MASK, chan->pwm_resolution_sel); in lpg_apply_freq()
565 val |= FIELD_PREP(PWM_SIZE_HI_RES_MASK, chan->pwm_resolution_sel); in lpg_apply_freq()
573 regmap_write(lpg->map, chan->base + LPG_SIZE_CLK_REG, val); in lpg_apply_freq()
575 val = FIELD_PREP(PWM_FREQ_PRE_DIV_MASK, chan->pre_div_sel) | in lpg_apply_freq()
576 FIELD_PREP(PWM_FREQ_EXP_MASK, chan->pre_div_exp); in lpg_apply_freq()
577 regmap_write(lpg->map, chan->base + LPG_PREDIV_CLK_REG, val); in lpg_apply_freq()
584 struct lpg *lpg = chan->lpg; in lpg_enable_glitch()
586 regmap_update_bits(lpg->map, chan->base + PWM_TYPE_CONFIG_REG, in lpg_enable_glitch()
592 struct lpg *lpg = chan->lpg; in lpg_disable_glitch()
594 regmap_update_bits(lpg->map, chan->base + PWM_TYPE_CONFIG_REG, in lpg_disable_glitch()
601 struct lpg *lpg = chan->lpg; in lpg_apply_pwm_value()
602 u16 val = chan->pwm_value; in lpg_apply_pwm_value()
604 if (!chan->enabled) in lpg_apply_pwm_value()
607 regmap_bulk_write(lpg->map, chan->base + PWM_VALUE_REG, &val, sizeof(val)); in lpg_apply_pwm_value()
618 struct nvmem_device *lpg_chan_sdam = chan->lpg->lpg_chan_sdam; in lpg_sdam_apply_lut_control()
619 unsigned int lo_idx = chan->pattern_lo_idx; in lpg_sdam_apply_lut_control()
620 unsigned int hi_idx = chan->pattern_hi_idx; in lpg_sdam_apply_lut_control()
623 struct lpg *lpg = chan->lpg; in lpg_sdam_apply_lut_control()
625 if (!chan->ramp_enabled || chan->pattern_lo_idx == chan->pattern_hi_idx) in lpg_sdam_apply_lut_control()
628 hi_pause = DIV_ROUND_UP(chan->ramp_hi_pause_ms, chan->ramp_tick_ms); in lpg_sdam_apply_lut_control()
629 lo_pause = DIV_ROUND_UP(chan->ramp_lo_pause_ms, chan->ramp_tick_ms); in lpg_sdam_apply_lut_control()
631 if (!chan->ramp_oneshot) in lpg_sdam_apply_lut_control()
633 if (chan->ramp_hi_pause_ms && lpg->lut_sdam) in lpg_sdam_apply_lut_control()
635 if (chan->ramp_lo_pause_ms && lpg->lut_sdam) in lpg_sdam_apply_lut_control()
638 if (lpg->lut_sdam) { in lpg_sdam_apply_lut_control()
639 lut_offset = SDAM_LUT_SDAM_LUT_PATTERN_OFFSET - SDAM_START_BASE; in lpg_sdam_apply_lut_control()
644 …nvmem_device_write(lpg_chan_sdam, SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET + chan->sdam_offset, 1, &val… in lpg_sdam_apply_lut_control()
645 nvmem_device_write(lpg_chan_sdam, SDAM_PATTERN_CONFIG_OFFSET + chan->sdam_offset, 1, &conf); in lpg_sdam_apply_lut_control()
646 nvmem_device_write(lpg_chan_sdam, SDAM_END_INDEX_OFFSET + chan->sdam_offset, 1, &hi_idx); in lpg_sdam_apply_lut_control()
647 nvmem_device_write(lpg_chan_sdam, SDAM_START_INDEX_OFFSET + chan->sdam_offset, 1, &lo_idx); in lpg_sdam_apply_lut_control()
649 val = RAMP_STEP_DURATION(chan->ramp_tick_ms); in lpg_sdam_apply_lut_control()
652 if (lpg->lut_sdam) { in lpg_sdam_apply_lut_control()
653 …nvmem_device_write(lpg_chan_sdam, SDAM_PAUSE_HI_MULTIPLIER_OFFSET + chan->sdam_offset, 1, &hi_paus… in lpg_sdam_apply_lut_control()
654 …nvmem_device_write(lpg_chan_sdam, SDAM_PAUSE_LO_MULTIPLIER_OFFSET + chan->sdam_offset, 1, &lo_paus… in lpg_sdam_apply_lut_control()
661 struct lpg *lpg = chan->lpg; in lpg_apply_lut_control()
665 unsigned int lo_idx = chan->pattern_lo_idx; in lpg_apply_lut_control()
666 unsigned int hi_idx = chan->pattern_hi_idx; in lpg_apply_lut_control()
667 u16 step = chan->ramp_tick_ms; in lpg_apply_lut_control()
669 if (!chan->ramp_enabled || chan->pattern_lo_idx == chan->pattern_hi_idx) in lpg_apply_lut_control()
672 hi_pause = DIV_ROUND_UP(chan->ramp_hi_pause_ms, step); in lpg_apply_lut_control()
673 lo_pause = DIV_ROUND_UP(chan->ramp_lo_pause_ms, step); in lpg_apply_lut_control()
675 if (!chan->ramp_reverse) in lpg_apply_lut_control()
677 if (!chan->ramp_oneshot) in lpg_apply_lut_control()
679 if (chan->ramp_ping_pong) in lpg_apply_lut_control()
681 if (chan->ramp_hi_pause_ms) in lpg_apply_lut_control()
683 if (chan->ramp_lo_pause_ms) in lpg_apply_lut_control()
686 regmap_write(lpg->map, chan->base + LPG_PATTERN_CONFIG_REG, conf); in lpg_apply_lut_control()
687 regmap_write(lpg->map, chan->base + LPG_HI_IDX_REG, hi_idx); in lpg_apply_lut_control()
688 regmap_write(lpg->map, chan->base + LPG_LO_IDX_REG, lo_idx); in lpg_apply_lut_control()
690 regmap_bulk_write(lpg->map, chan->base + LPG_RAMP_DURATION_REG, &step, sizeof(step)); in lpg_apply_lut_control()
691 regmap_write(lpg->map, chan->base + LPG_HI_PAUSE_REG, hi_pause); in lpg_apply_lut_control()
692 regmap_write(lpg->map, chan->base + LPG_LO_PAUSE_REG, lo_pause); in lpg_apply_lut_control()
703 struct lpg *lpg = chan->lpg; in lpg_apply_control()
707 if (chan->enabled) in lpg_apply_control()
710 if (chan->pattern_lo_idx != chan->pattern_hi_idx) in lpg_apply_control()
715 regmap_write(lpg->map, chan->base + PWM_ENABLE_CONTROL_REG, ctrl); in lpg_apply_control()
718 * Due to LPG hardware bug, in the PWM mode, having enabled PWM, in lpg_apply_control()
719 * We have to write PWM values one more time. in lpg_apply_control()
721 if (chan->enabled) in lpg_apply_control()
729 struct lpg *lpg = chan->lpg; in lpg_apply_sync()
731 regmap_write(lpg->map, chan->base + PWM_SYNC_REG, LPG_SYNC_PWM); in lpg_apply_sync()
737 struct device_node *np = lpg->dev->of_node; in lpg_parse_dtest()
743 if (count == -EINVAL) { in lpg_parse_dtest()
748 } else if (count != lpg->data->num_channels * 2) { in lpg_parse_dtest()
749 return dev_err_probe(lpg->dev, -EINVAL, in lpg_parse_dtest()
751 lpg->data->num_channels * 2); in lpg_parse_dtest()
754 for (i = 0; i < lpg->data->num_channels; i++) { in lpg_parse_dtest()
755 chan = &lpg->channels[i]; in lpg_parse_dtest()
758 &chan->dtest_line); in lpg_parse_dtest()
763 &chan->dtest_value); in lpg_parse_dtest()
771 return dev_err_probe(lpg->dev, ret, "malformed qcom,dtest\n"); in lpg_parse_dtest()
776 struct lpg *lpg = chan->lpg; in lpg_apply_dtest()
778 if (!chan->dtest_line) in lpg_apply_dtest()
781 regmap_write(lpg->map, chan->base + PWM_SEC_ACCESS_REG, 0xa5); in lpg_apply_dtest()
782 regmap_write(lpg->map, chan->base + PWM_DTEST_REG(chan->dtest_line), in lpg_apply_dtest()
783 chan->dtest_value); in lpg_apply_dtest()
793 if (chan->lpg->lpg_chan_sdam) in lpg_apply()
809 struct lpg *lpg = led->lpg; in lpg_brightness_set()
812 for (i = 0; i < led->num_channels; i++) { in lpg_brightness_set()
813 chan = led->channels[i]; in lpg_brightness_set()
817 chan->enabled = false; in lpg_brightness_set()
818 chan->ramp_enabled = false; in lpg_brightness_set()
819 } else if (chan->pattern_lo_idx != chan->pattern_hi_idx) { in lpg_brightness_set()
823 chan->enabled = true; in lpg_brightness_set()
824 chan->ramp_enabled = true; in lpg_brightness_set()
826 lut_mask |= chan->lut_mask; in lpg_brightness_set()
827 triled_enabled |= chan->triled_mask; in lpg_brightness_set()
831 duty = div_u64(brightness * chan->period, cdev->max_brightness); in lpg_brightness_set()
833 chan->enabled = true; in lpg_brightness_set()
834 chan->ramp_enabled = false; in lpg_brightness_set()
836 triled_enabled |= chan->triled_mask; in lpg_brightness_set()
839 triled_mask |= chan->triled_mask; in lpg_brightness_set()
861 mutex_lock(&led->lpg->lock); in lpg_brightness_single_set()
866 mutex_unlock(&led->lpg->lock); in lpg_brightness_single_set()
877 mutex_lock(&led->lpg->lock); in lpg_brightness_mc_set()
880 lpg_brightness_set(led, cdev, mc->subled_info); in lpg_brightness_mc_set()
882 mutex_unlock(&led->lpg->lock); in lpg_brightness_mc_set()
893 struct lpg *lpg = led->lpg; in lpg_blink_set()
905 for (i = 0; i < led->num_channels; i++) { in lpg_blink_set()
906 chan = led->channels[i]; in lpg_blink_set()
911 chan->enabled = true; in lpg_blink_set()
912 chan->ramp_enabled = false; in lpg_blink_set()
914 triled_mask |= chan->triled_mask; in lpg_blink_set()
922 chan = led->channels[0]; in lpg_blink_set()
923 duty = div_u64(chan->pwm_value * chan->period, LPG_RESOLUTION_9BIT); in lpg_blink_set()
925 *delay_off = div_u64(chan->period - duty, NSEC_PER_MSEC); in lpg_blink_set()
936 mutex_lock(&led->lpg->lock); in lpg_blink_single_set()
940 mutex_unlock(&led->lpg->lock); in lpg_blink_single_set()
952 mutex_lock(&led->lpg->lock); in lpg_blink_mc_set()
956 mutex_unlock(&led->lpg->lock); in lpg_blink_mc_set()
965 struct lpg *lpg = led->lpg; in lpg_pattern_set()
977 int ret = -EINVAL; in lpg_pattern_set()
980 if (repeat != -1 && repeat != 1) in lpg_pattern_set()
981 return -EINVAL; in lpg_pattern_set()
984 * The standardized leds-trigger-pattern format defines that the in lpg_pattern_set()
987 * describes that the way to perform instant transitions a zero-length in lpg_pattern_set()
992 * a zero-length transition. in lpg_pattern_set()
995 return -EINVAL; in lpg_pattern_set()
999 return -ENOMEM; in lpg_pattern_set()
1039 * SDAM-based devices do not support "ping pong", and only supports in lpg_pattern_set()
1044 if (lpg->lut_base) { in lpg_pattern_set()
1047 brightness_b = pattern[len - i - 1].brightness; in lpg_pattern_set()
1074 if (i != actual_len - 1) in lpg_pattern_set()
1085 * SDAM-based devices without dedicated LUT SDAM require equal in lpg_pattern_set()
1088 if (lpg->lut_base || lpg->lut_sdam) { in lpg_pattern_set()
1090 hi_pause = pattern[actual_len - 1].delta_t; in lpg_pattern_set()
1092 if (delta_t != pattern[0].delta_t || delta_t != pattern[actual_len - 1].delta_t) in lpg_pattern_set()
1097 mutex_lock(&lpg->lock); in lpg_pattern_set()
1099 if (lpg->lut_base) in lpg_pattern_set()
1107 for (i = 0; i < led->num_channels; i++) { in lpg_pattern_set()
1108 chan = led->channels[i]; in lpg_pattern_set()
1110 chan->ramp_tick_ms = delta_t; in lpg_pattern_set()
1111 chan->ramp_ping_pong = ping_pong; in lpg_pattern_set()
1112 chan->ramp_oneshot = repeat != -1; in lpg_pattern_set()
1114 chan->ramp_lo_pause_ms = lo_pause; in lpg_pattern_set()
1115 chan->ramp_hi_pause_ms = hi_pause; in lpg_pattern_set()
1117 chan->pattern_lo_idx = lo_idx; in lpg_pattern_set()
1118 chan->pattern_hi_idx = hi_idx; in lpg_pattern_set()
1122 mutex_unlock(&lpg->lock); in lpg_pattern_set()
1154 for (i = 0; i < led->num_channels; i++) in lpg_pattern_mc_set()
1155 triled_mask |= led->channels[i]->triled_mask; in lpg_pattern_mc_set()
1156 triled_set(led->lpg, triled_mask, 0); in lpg_pattern_mc_set()
1163 lpg_brightness_set(led, cdev, mc->subled_info); in lpg_pattern_mc_set()
1171 struct lpg *lpg = led->lpg; in lpg_pattern_clear()
1174 mutex_lock(&lpg->lock); in lpg_pattern_clear()
1176 chan = led->channels[0]; in lpg_pattern_clear()
1177 lpg_lut_free(lpg, chan->pattern_lo_idx, chan->pattern_hi_idx); in lpg_pattern_clear()
1179 for (i = 0; i < led->num_channels; i++) { in lpg_pattern_clear()
1180 chan = led->channels[i]; in lpg_pattern_clear()
1182 lpg_clear_pbs_trigger(chan->lpg, chan->lut_mask); in lpg_pattern_clear()
1183 chan->pattern_lo_idx = 0; in lpg_pattern_clear()
1184 chan->pattern_hi_idx = 0; in lpg_pattern_clear()
1187 mutex_unlock(&lpg->lock); in lpg_pattern_clear()
1212 static int lpg_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) in lpg_pwm_request() argument
1215 struct lpg_channel *chan = &lpg->channels[pwm->hwpwm]; in lpg_pwm_request()
1217 return chan->in_use ? -EBUSY : 0; in lpg_pwm_request()
1222 * - Updating both duty and period is not done atomically, so the output signal
1224 * - Changed parameters takes effect immediately.
1225 * - A disabled channel outputs a logical 0.
1227 static int lpg_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, in lpg_pwm_apply() argument
1231 struct lpg_channel *chan = &lpg->channels[pwm->hwpwm]; in lpg_pwm_apply()
1234 if (state->polarity != PWM_POLARITY_NORMAL) in lpg_pwm_apply()
1235 return -EINVAL; in lpg_pwm_apply()
1237 mutex_lock(&lpg->lock); in lpg_pwm_apply()
1239 if (state->enabled) { in lpg_pwm_apply()
1240 ret = lpg_calc_freq(chan, state->period); in lpg_pwm_apply()
1244 lpg_calc_duty(chan, state->duty_cycle); in lpg_pwm_apply()
1246 chan->enabled = state->enabled; in lpg_pwm_apply()
1250 triled_set(lpg, chan->triled_mask, chan->enabled ? chan->triled_mask : 0); in lpg_pwm_apply()
1253 mutex_unlock(&lpg->lock); in lpg_pwm_apply()
1258 static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, in lpg_pwm_get_state() argument
1262 struct lpg_channel *chan = &lpg->channels[pwm->hwpwm]; in lpg_pwm_get_state()
1271 ret = regmap_read(lpg->map, chan->base + LPG_SIZE_CLK_REG, &val); in lpg_pwm_get_state()
1275 if (chan->subtype == LPG_SUBTYPE_HI_RES_PWM) { in lpg_pwm_get_state()
1284 ret = regmap_read(lpg->map, chan->base + LPG_PREDIV_CLK_REG, &val); in lpg_pwm_get_state()
1291 ret = regmap_bulk_read(lpg->map, chan->base + PWM_VALUE_REG, &pwm_value, sizeof(pwm_value)); in lpg_pwm_get_state()
1295 state->period = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * ((1 << resolution) - 1) * in lpg_pwm_get_state()
1297 state->duty_cycle = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * pwm_value * pre_div * (1 << m), refclk); in lpg_pwm_get_state()
1299 state->period = 0; in lpg_pwm_get_state()
1300 state->duty_cycle = 0; in lpg_pwm_get_state()
1303 ret = regmap_read(lpg->map, chan->base + PWM_ENABLE_CONTROL_REG, &val); in lpg_pwm_get_state()
1307 state->enabled = FIELD_GET(LPG_ENABLE_CONTROL_OUTPUT, val); in lpg_pwm_get_state()
1308 state->polarity = PWM_POLARITY_NORMAL; in lpg_pwm_get_state()
1310 if (state->duty_cycle > state->period) in lpg_pwm_get_state()
1311 state->duty_cycle = state->period; in lpg_pwm_get_state()
1327 lpg->pwm = chip = devm_pwmchip_alloc(lpg->dev, lpg->num_channels, 0); in lpg_add_pwm()
1331 chip->ops = &lpg_pwm_ops; in lpg_add_pwm()
1334 ret = devm_pwmchip_add(lpg->dev, chip); in lpg_add_pwm()
1336 dev_err_probe(lpg->dev, ret, "failed to add PWM chip\n"); in lpg_add_pwm()
1350 if (ret || !reg || reg > lpg->num_channels) in lpg_parse_channel()
1351 return dev_err_probe(lpg->dev, -EINVAL, "invalid \"reg\" of %pOFn\n", np); in lpg_parse_channel()
1353 chan = &lpg->channels[reg - 1]; in lpg_parse_channel()
1354 chan->in_use = true; in lpg_parse_channel()
1357 if (ret < 0 && ret != -EINVAL) in lpg_parse_channel()
1358 return dev_err_probe(lpg->dev, ret, in lpg_parse_channel()
1361 chan->color = color; in lpg_parse_channel()
1381 if (ret < 0 && ret != -EINVAL) in lpg_add_led()
1382 return dev_err_probe(lpg->dev, ret, in lpg_add_led()
1390 led = devm_kzalloc(lpg->dev, struct_size(led, channels, num_channels), GFP_KERNEL); in lpg_add_led()
1392 return -ENOMEM; in lpg_add_led()
1394 led->lpg = lpg; in lpg_add_led()
1395 led->num_channels = num_channels; in lpg_add_led()
1398 info = devm_kcalloc(lpg->dev, num_channels, sizeof(*info), GFP_KERNEL); in lpg_add_led()
1400 return -ENOMEM; in lpg_add_led()
1403 ret = lpg_parse_channel(lpg, child, &led->channels[i]); in lpg_add_led()
1407 info[i].color_index = led->channels[i]->color; in lpg_add_led()
1412 led->mcdev.subled_info = info; in lpg_add_led()
1413 led->mcdev.num_colors = num_channels; in lpg_add_led()
1415 cdev = &led->mcdev.led_cdev; in lpg_add_led()
1416 cdev->brightness_set_blocking = lpg_brightness_mc_set; in lpg_add_led()
1417 cdev->blink_set = lpg_blink_mc_set; in lpg_add_led()
1420 if (lpg->lut_base || lpg->lpg_chan_sdam) { in lpg_add_led()
1421 cdev->pattern_set = lpg_pattern_mc_set; in lpg_add_led()
1422 cdev->pattern_clear = lpg_pattern_mc_clear; in lpg_add_led()
1425 ret = lpg_parse_channel(lpg, np, &led->channels[0]); in lpg_add_led()
1429 cdev = &led->cdev; in lpg_add_led()
1430 cdev->brightness_set_blocking = lpg_brightness_single_set; in lpg_add_led()
1431 cdev->blink_set = lpg_blink_single_set; in lpg_add_led()
1434 if (lpg->lut_base || lpg->lpg_chan_sdam) { in lpg_add_led()
1435 cdev->pattern_set = lpg_pattern_single_set; in lpg_add_led()
1436 cdev->pattern_clear = lpg_pattern_single_clear; in lpg_add_led()
1440 cdev->default_trigger = of_get_property(np, "linux,default-trigger", NULL); in lpg_add_led()
1442 if (lpg->lpg_chan_sdam) in lpg_add_led()
1443 cdev->max_brightness = PPG_MAX_LED_BRIGHTNESS; in lpg_add_led()
1445 cdev->max_brightness = LPG_RESOLUTION_9BIT - 1; in lpg_add_led()
1447 if (!of_property_read_string(np, "default-state", &state) && in lpg_add_led()
1449 cdev->brightness = cdev->max_brightness; in lpg_add_led()
1451 cdev->brightness = LED_OFF; in lpg_add_led()
1453 cdev->brightness_set_blocking(cdev, cdev->brightness); in lpg_add_led()
1458 ret = devm_led_classdev_multicolor_register_ext(lpg->dev, &led->mcdev, &init_data); in lpg_add_led()
1460 ret = devm_led_classdev_register_ext(lpg->dev, &led->cdev, &init_data); in lpg_add_led()
1462 dev_err_probe(lpg->dev, ret, "unable to register %s\n", cdev->name); in lpg_add_led()
1469 const struct lpg_data *data = lpg->data; in lpg_init_channels()
1473 lpg->num_channels = data->num_channels; in lpg_init_channels()
1474 lpg->channels = devm_kcalloc(lpg->dev, data->num_channels, in lpg_init_channels()
1476 if (!lpg->channels) in lpg_init_channels()
1477 return -ENOMEM; in lpg_init_channels()
1479 for (i = 0; i < data->num_channels; i++) { in lpg_init_channels()
1480 chan = &lpg->channels[i]; in lpg_init_channels()
1482 chan->lpg = lpg; in lpg_init_channels()
1483 chan->base = data->channels[i].base; in lpg_init_channels()
1484 chan->triled_mask = data->channels[i].triled_mask; in lpg_init_channels()
1485 chan->lut_mask = BIT(i); in lpg_init_channels()
1486 chan->sdam_offset = data->channels[i].sdam_offset; in lpg_init_channels()
1488 regmap_read(lpg->map, chan->base + LPG_SUBTYPE_REG, &chan->subtype); in lpg_init_channels()
1496 struct device_node *np = lpg->dev->of_node; in lpg_init_triled()
1500 if (!lpg->data->triled_base) in lpg_init_triled()
1503 lpg->triled_base = lpg->data->triled_base; in lpg_init_triled()
1504 lpg->triled_has_atc_ctl = lpg->data->triled_has_atc_ctl; in lpg_init_triled()
1505 lpg->triled_has_src_sel = lpg->data->triled_has_src_sel; in lpg_init_triled()
1507 if (lpg->triled_has_src_sel) { in lpg_init_triled()
1508 ret = of_property_read_u32(np, "qcom,power-source", &lpg->triled_src); in lpg_init_triled()
1509 if (ret || lpg->triled_src == 2 || lpg->triled_src > 3) in lpg_init_triled()
1510 return dev_err_probe(lpg->dev, -EINVAL, in lpg_init_triled()
1515 if (lpg->triled_has_atc_ctl) in lpg_init_triled()
1516 regmap_write(lpg->map, lpg->triled_base + TRI_LED_ATC_CTL, 0); in lpg_init_triled()
1519 if (lpg->triled_has_src_sel) in lpg_init_triled()
1520 regmap_write(lpg->map, lpg->triled_base + TRI_LED_SRC_SEL, lpg->triled_src); in lpg_init_triled()
1523 regmap_write(lpg->map, lpg->triled_base + TRI_LED_EN_CTL, 0); in lpg_init_triled()
1530 const struct lpg_data *data = lpg->data; in lpg_init_lut()
1532 if (!data->lut_size) in lpg_init_lut()
1535 lpg->lut_size = data->lut_size; in lpg_init_lut()
1536 if (data->lut_base) in lpg_init_lut()
1537 lpg->lut_base = data->lut_base; in lpg_init_lut()
1539 lpg->lut_bitmap = devm_bitmap_zalloc(lpg->dev, lpg->lut_size, GFP_KERNEL); in lpg_init_lut()
1540 if (!lpg->lut_bitmap) in lpg_init_lut()
1541 return -ENOMEM; in lpg_init_lut()
1551 sdam_count = of_property_count_strings(lpg->dev->of_node, "nvmem-names"); in lpg_init_sdam()
1555 return -EINVAL; in lpg_init_sdam()
1558 lpg->lpg_chan_sdam = devm_nvmem_device_get(lpg->dev, "lpg_chan_sdam"); in lpg_init_sdam()
1559 if (IS_ERR(lpg->lpg_chan_sdam)) in lpg_init_sdam()
1560 return dev_err_probe(lpg->dev, PTR_ERR(lpg->lpg_chan_sdam), in lpg_init_sdam()
1565 lpg->pbs_dev = get_pbs_client_device(lpg->dev); in lpg_init_sdam()
1566 if (IS_ERR(lpg->pbs_dev)) in lpg_init_sdam()
1567 return dev_err_probe(lpg->dev, PTR_ERR(lpg->pbs_dev), in lpg_init_sdam()
1571 lpg->lut_sdam = devm_nvmem_device_get(lpg->dev, "lut_sdam"); in lpg_init_sdam()
1572 if (IS_ERR(lpg->lut_sdam)) in lpg_init_sdam()
1573 return dev_err_probe(lpg->dev, PTR_ERR(lpg->lut_sdam), in lpg_init_sdam()
1577 for (i = 0; i < lpg->num_channels; i++) { in lpg_init_sdam()
1578 struct lpg_channel *chan = &lpg->channels[i]; in lpg_init_sdam()
1580 if (chan->sdam_offset) { in lpg_init_sdam()
1581 rc = nvmem_device_write(lpg->lpg_chan_sdam, in lpg_init_sdam()
1582 SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET + chan->sdam_offset, 1, &val); in lpg_init_sdam()
1590 rc = lpg_clear_pbs_trigger(chan->lpg, chan->lut_mask); in lpg_init_sdam()
1605 lpg = devm_kzalloc(&pdev->dev, sizeof(*lpg), GFP_KERNEL); in lpg_probe()
1607 return -ENOMEM; in lpg_probe()
1609 lpg->data = of_device_get_match_data(&pdev->dev); in lpg_probe()
1610 if (!lpg->data) in lpg_probe()
1611 return -EINVAL; in lpg_probe()
1613 lpg->dev = &pdev->dev; in lpg_probe()
1614 mutex_init(&lpg->lock); in lpg_probe()
1616 lpg->map = dev_get_regmap(pdev->dev.parent, NULL); in lpg_probe()
1617 if (!lpg->map) in lpg_probe()
1618 return dev_err_probe(&pdev->dev, -ENXIO, "parent regmap unavailable\n"); in lpg_probe()
1640 for_each_available_child_of_node_scoped(pdev->dev.of_node, np) { in lpg_probe()
1646 for (i = 0; i < lpg->num_channels; i++) in lpg_probe()
1647 lpg_apply_dtest(&lpg->channels[i]); in lpg_probe()
1822 { .compatible = "qcom,pm660l-lpg", .data = &pm660l_lpg_data },
1823 { .compatible = "qcom,pm8150b-lpg", .data = &pm8150b_lpg_data },
1824 { .compatible = "qcom,pm8150l-lpg", .data = &pm8150l_lpg_data },
1825 { .compatible = "qcom,pm8350c-pwm", .data = &pm8350c_pwm_data },
1826 { .compatible = "qcom,pm8916-pwm", .data = &pm8916_pwm_data },
1827 { .compatible = "qcom,pm8941-lpg", .data = &pm8941_lpg_data },
1828 { .compatible = "qcom,pm8994-lpg", .data = &pm8994_lpg_data },
1829 { .compatible = "qcom,pmi632-lpg", .data = &pmi632_lpg_data },
1830 { .compatible = "qcom,pmi8950-pwm", .data = &pmi8950_pwm_data },
1831 { .compatible = "qcom,pmi8994-lpg", .data = &pmi8994_lpg_data },
1832 { .compatible = "qcom,pmi8998-lpg", .data = &pmi8998_lpg_data },
1833 { .compatible = "qcom,pmc8180c-lpg", .data = &pm8150l_lpg_data },
1834 { .compatible = "qcom,pmk8550-pwm", .data = &pmk8550_pwm_data },
1842 .name = "qcom-spmi-lpg",