Lines Matching full:lpg

66 /* LPG common config settings for PPG */
73 /* LPG per channel config settings for PPG */
86 * struct lpg - LPG device context
87 * @dev: pointer to LPG device
96 * @lpg_chan_sdam: LPG SDAM peripheral device
106 struct lpg { struct
136 * @lpg: reference to parent lpg argument
141 * @sdam_offset: channel offset in LPG SDAM
164 struct lpg *lpg; member
202 * @lpg: lpg context reference
209 struct lpg *lpg; member
220 * @sdam_offset: Channel offset in LPG SDAM
237 * @num_channels: number of channels in LPG
252 static int lpg_clear_pbs_trigger(struct lpg *lpg, unsigned int lut_mask) in lpg_clear_pbs_trigger() argument
257 if (!lpg->lpg_chan_sdam) in lpg_clear_pbs_trigger()
260 lpg->pbs_en_bitmap &= (~lut_mask); in lpg_clear_pbs_trigger()
261 if (!lpg->pbs_en_bitmap) { in lpg_clear_pbs_trigger()
262 rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_REG_PBS_SEQ_EN, 1, &val); in lpg_clear_pbs_trigger()
266 if (lpg->lut_sdam) { in lpg_clear_pbs_trigger()
268 rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_PBS_TRIG_CLR, 1, &val); in lpg_clear_pbs_trigger()
277 static int lpg_set_pbs_trigger(struct lpg *lpg, unsigned int lut_mask) in lpg_set_pbs_trigger() argument
282 if (!lpg->lpg_chan_sdam) in lpg_set_pbs_trigger()
285 if (!lpg->pbs_en_bitmap) { in lpg_set_pbs_trigger()
286 rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_REG_PBS_SEQ_EN, 1, &val); in lpg_set_pbs_trigger()
290 if (lpg->lut_sdam) { in lpg_set_pbs_trigger()
291 rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_PBS_TRIG_SET, 1, &val); in lpg_set_pbs_trigger()
295 rc = qcom_pbs_trigger_event(lpg->pbs_dev, val); in lpg_set_pbs_trigger()
300 lpg->pbs_en_bitmap |= lut_mask; in lpg_set_pbs_trigger()
309 if (!chan->lpg->lpg_chan_sdam) in lpg_sdam_configure_triggers()
312 return nvmem_device_write(chan->lpg->lpg_chan_sdam, addr, 1, &set_trig); in lpg_sdam_configure_triggers()
315 static int triled_set(struct lpg *lpg, unsigned int mask, unsigned int enable) in triled_set() argument
318 if (!lpg->triled_base) in triled_set()
321 return regmap_update_bits(lpg->map, lpg->triled_base + TRI_LED_EN_CTL, in triled_set()
325 static int lpg_lut_store_sdam(struct lpg *lpg, struct led_pattern *pattern, in lpg_lut_store_sdam() argument
333 if (len > lpg->lut_size) { in lpg_lut_store_sdam()
334 dev_err(lpg->dev, "Pattern length (%zu) exceeds maximum pattern length (%d)\n", in lpg_lut_store_sdam()
335 len, lpg->lut_size); in lpg_lut_store_sdam()
339 idx = bitmap_find_next_zero_area(lpg->lut_bitmap, lpg->lut_size, 0, len, 0); in lpg_lut_store_sdam()
340 if (idx >= lpg->lut_size) in lpg_lut_store_sdam()
346 if (lpg->lut_sdam) { in lpg_lut_store_sdam()
348 rc = nvmem_device_write(lpg->lut_sdam, addr, 1, &brightness); in lpg_lut_store_sdam()
351 rc = nvmem_device_write(lpg->lpg_chan_sdam, addr, 1, &brightness); in lpg_lut_store_sdam()
358 bitmap_set(lpg->lut_bitmap, idx, len); in lpg_lut_store_sdam()
366 static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern, in lpg_lut_store() argument
373 idx = bitmap_find_next_zero_area(lpg->lut_bitmap, lpg->lut_size, in lpg_lut_store()
375 if (idx >= lpg->lut_size) in lpg_lut_store()
381 regmap_bulk_write(lpg->map, lpg->lut_base + LPG_LUT_REG(idx + i), in lpg_lut_store()
385 bitmap_set(lpg->lut_bitmap, idx, len); in lpg_lut_store()
393 static void lpg_lut_free(struct lpg *lpg, unsigned int lo_idx, unsigned int hi_idx) in lpg_lut_free() argument
401 bitmap_clear(lpg->lut_bitmap, lo_idx, len); in lpg_lut_free()
404 static int lpg_lut_sync(struct lpg *lpg, unsigned int mask) in lpg_lut_sync() argument
406 if (!lpg->lut_base) in lpg_lut_sync()
409 return regmap_write(lpg->map, lpg->lut_base + RAMP_CONTROL_REG, mask); in lpg_lut_sync()
548 struct lpg *lpg = chan->lpg; in lpg_apply_freq() local
572 regmap_write(lpg->map, chan->base + LPG_SIZE_CLK_REG, val); in lpg_apply_freq()
576 regmap_write(lpg->map, chan->base + LPG_PREDIV_CLK_REG, val); in lpg_apply_freq()
583 struct lpg *lpg = chan->lpg; in lpg_enable_glitch() local
585 regmap_update_bits(lpg->map, chan->base + PWM_TYPE_CONFIG_REG, in lpg_enable_glitch()
591 struct lpg *lpg = chan->lpg; in lpg_disable_glitch() local
593 regmap_update_bits(lpg->map, chan->base + PWM_TYPE_CONFIG_REG, in lpg_disable_glitch()
600 struct lpg *lpg = chan->lpg; in lpg_apply_pwm_value() local
606 regmap_bulk_write(lpg->map, chan->base + PWM_VALUE_REG, &val, sizeof(val)); in lpg_apply_pwm_value()
617 struct nvmem_device *lpg_chan_sdam = chan->lpg->lpg_chan_sdam; in lpg_sdam_apply_lut_control()
622 struct lpg *lpg = chan->lpg; in lpg_sdam_apply_lut_control() local
632 if (chan->ramp_hi_pause_ms && lpg->lut_sdam) in lpg_sdam_apply_lut_control()
634 if (chan->ramp_lo_pause_ms && lpg->lut_sdam) in lpg_sdam_apply_lut_control()
637 if (lpg->lut_sdam) { in lpg_sdam_apply_lut_control()
651 if (lpg->lut_sdam) { in lpg_sdam_apply_lut_control()
660 struct lpg *lpg = chan->lpg; in lpg_apply_lut_control() local
685 regmap_write(lpg->map, chan->base + LPG_PATTERN_CONFIG_REG, conf); in lpg_apply_lut_control()
686 regmap_write(lpg->map, chan->base + LPG_HI_IDX_REG, hi_idx); in lpg_apply_lut_control()
687 regmap_write(lpg->map, chan->base + LPG_LO_IDX_REG, lo_idx); in lpg_apply_lut_control()
689 regmap_bulk_write(lpg->map, chan->base + LPG_RAMP_DURATION_REG, &step, sizeof(step)); in lpg_apply_lut_control()
690 regmap_write(lpg->map, chan->base + LPG_HI_PAUSE_REG, hi_pause); in lpg_apply_lut_control()
691 regmap_write(lpg->map, chan->base + LPG_LO_PAUSE_REG, lo_pause); in lpg_apply_lut_control()
702 struct lpg *lpg = chan->lpg; in lpg_apply_control() local
714 regmap_write(lpg->map, chan->base + PWM_ENABLE_CONTROL_REG, ctrl); in lpg_apply_control()
717 * Due to LPG hardware bug, in the PWM mode, having enabled PWM, in lpg_apply_control()
728 struct lpg *lpg = chan->lpg; in lpg_apply_sync() local
730 regmap_write(lpg->map, chan->base + PWM_SYNC_REG, LPG_SYNC_PWM); in lpg_apply_sync()
733 static int lpg_parse_dtest(struct lpg *lpg) in lpg_parse_dtest() argument
736 struct device_node *np = lpg->dev->of_node; in lpg_parse_dtest()
747 } else if (count != lpg->data->num_channels * 2) { in lpg_parse_dtest()
748 return dev_err_probe(lpg->dev, -EINVAL, in lpg_parse_dtest()
750 lpg->data->num_channels * 2); in lpg_parse_dtest()
753 for (i = 0; i < lpg->data->num_channels; i++) { in lpg_parse_dtest()
754 chan = &lpg->channels[i]; in lpg_parse_dtest()
770 return dev_err_probe(lpg->dev, ret, "malformed qcom,dtest\n"); in lpg_parse_dtest()
775 struct lpg *lpg = chan->lpg; in lpg_apply_dtest() local
780 regmap_write(lpg->map, chan->base + PWM_SEC_ACCESS_REG, 0xa5); in lpg_apply_dtest()
781 regmap_write(lpg->map, chan->base + PWM_DTEST_REG(chan->dtest_line), in lpg_apply_dtest()
792 if (chan->lpg->lpg_chan_sdam) in lpg_apply()
808 struct lpg *lpg = led->lpg; in lpg_brightness_set() local
845 triled_set(lpg, triled_mask, triled_enabled); in lpg_brightness_set()
849 lpg_lut_sync(lpg, lut_mask); in lpg_brightness_set()
850 lpg_set_pbs_trigger(lpg, lut_mask); in lpg_brightness_set()
860 mutex_lock(&led->lpg->lock); in lpg_brightness_single_set()
865 mutex_unlock(&led->lpg->lock); in lpg_brightness_single_set()
876 mutex_lock(&led->lpg->lock); in lpg_brightness_mc_set()
881 mutex_unlock(&led->lpg->lock); in lpg_brightness_mc_set()
892 struct lpg *lpg = led->lpg; in lpg_blink_set() local
919 triled_set(lpg, triled_mask, triled_mask); in lpg_blink_set()
935 mutex_lock(&led->lpg->lock); in lpg_blink_single_set()
939 mutex_unlock(&led->lpg->lock); in lpg_blink_single_set()
951 mutex_lock(&led->lpg->lock); in lpg_blink_mc_set()
955 mutex_unlock(&led->lpg->lock); in lpg_blink_mc_set()
964 struct lpg *lpg = led->lpg; in lpg_pattern_set() local
989 * The LPG hardware is only able to perform the latter (no linear in lpg_pattern_set()
1020 * The LPG plays patterns with at a fixed pace, a "low pause" can be in lpg_pattern_set()
1043 if (lpg->lut_base) { in lpg_pattern_set()
1087 if (lpg->lut_base || lpg->lut_sdam) { in lpg_pattern_set()
1096 mutex_lock(&lpg->lock); in lpg_pattern_set()
1098 if (lpg->lut_base) in lpg_pattern_set()
1099 ret = lpg_lut_store(lpg, pattern, actual_len, &lo_idx, &hi_idx); in lpg_pattern_set()
1101 ret = lpg_lut_store_sdam(lpg, pattern, actual_len, &lo_idx, &hi_idx); in lpg_pattern_set()
1121 mutex_unlock(&lpg->lock); in lpg_pattern_set()
1155 triled_set(led->lpg, triled_mask, 0); in lpg_pattern_mc_set()
1170 struct lpg *lpg = led->lpg; in lpg_pattern_clear() local
1173 mutex_lock(&lpg->lock); in lpg_pattern_clear()
1176 lpg_lut_free(lpg, chan->pattern_lo_idx, chan->pattern_hi_idx); in lpg_pattern_clear()
1181 lpg_clear_pbs_trigger(chan->lpg, chan->lut_mask); in lpg_pattern_clear()
1186 mutex_unlock(&lpg->lock); in lpg_pattern_clear()
1206 static inline struct lpg *lpg_pwm_from_chip(struct pwm_chip *chip) in lpg_pwm_from_chip()
1213 struct lpg *lpg = lpg_pwm_from_chip(chip); in lpg_pwm_request() local
1214 struct lpg_channel *chan = &lpg->channels[pwm->hwpwm]; in lpg_pwm_request()
1229 struct lpg *lpg = lpg_pwm_from_chip(chip); in lpg_pwm_apply() local
1230 struct lpg_channel *chan = &lpg->channels[pwm->hwpwm]; in lpg_pwm_apply()
1236 mutex_lock(&lpg->lock); in lpg_pwm_apply()
1249 triled_set(lpg, chan->triled_mask, chan->enabled ? chan->triled_mask : 0); in lpg_pwm_apply()
1252 mutex_unlock(&lpg->lock); in lpg_pwm_apply()
1260 struct lpg *lpg = lpg_pwm_from_chip(chip); in lpg_pwm_get_state() local
1261 struct lpg_channel *chan = &lpg->channels[pwm->hwpwm]; in lpg_pwm_get_state()
1270 ret = regmap_read(lpg->map, chan->base + LPG_SIZE_CLK_REG, &val); in lpg_pwm_get_state()
1283 ret = regmap_read(lpg->map, chan->base + LPG_PREDIV_CLK_REG, &val); in lpg_pwm_get_state()
1290 ret = regmap_bulk_read(lpg->map, chan->base + PWM_VALUE_REG, &pwm_value, sizeof(pwm_value)); in lpg_pwm_get_state()
1302 ret = regmap_read(lpg->map, chan->base + PWM_ENABLE_CONTROL_REG, &val); in lpg_pwm_get_state()
1321 static int lpg_add_pwm(struct lpg *lpg) in lpg_add_pwm() argument
1326 lpg->pwm = chip = devm_pwmchip_alloc(lpg->dev, lpg->num_channels, 0); in lpg_add_pwm()
1331 pwmchip_set_drvdata(chip, lpg); in lpg_add_pwm()
1333 ret = devm_pwmchip_add(lpg->dev, chip); in lpg_add_pwm()
1335 dev_err_probe(lpg->dev, ret, "failed to add PWM chip\n"); in lpg_add_pwm()
1340 static int lpg_parse_channel(struct lpg *lpg, struct device_node *np, in lpg_parse_channel() argument
1349 if (ret || !reg || reg > lpg->num_channels) in lpg_parse_channel()
1350 return dev_err_probe(lpg->dev, -EINVAL, "invalid \"reg\" of %pOFn\n", np); in lpg_parse_channel()
1352 chan = &lpg->channels[reg - 1]; in lpg_parse_channel()
1357 return dev_err_probe(lpg->dev, ret, in lpg_parse_channel()
1367 static int lpg_add_led(struct lpg *lpg, struct device_node *np) in lpg_add_led() argument
1381 return dev_err_probe(lpg->dev, ret, in lpg_add_led()
1389 led = devm_kzalloc(lpg->dev, struct_size(led, channels, num_channels), GFP_KERNEL); in lpg_add_led()
1393 led->lpg = lpg; in lpg_add_led()
1397 info = devm_kcalloc(lpg->dev, num_channels, sizeof(*info), GFP_KERNEL); in lpg_add_led()
1402 ret = lpg_parse_channel(lpg, child, &led->channels[i]); in lpg_add_led()
1419 if (lpg->lut_base || lpg->lpg_chan_sdam) { in lpg_add_led()
1424 ret = lpg_parse_channel(lpg, np, &led->channels[0]); in lpg_add_led()
1433 if (lpg->lut_base || lpg->lpg_chan_sdam) { in lpg_add_led()
1441 if (lpg->lpg_chan_sdam) in lpg_add_led()
1457 ret = devm_led_classdev_multicolor_register_ext(lpg->dev, &led->mcdev, &init_data); in lpg_add_led()
1459 ret = devm_led_classdev_register_ext(lpg->dev, &led->cdev, &init_data); in lpg_add_led()
1461 dev_err_probe(lpg->dev, ret, "unable to register %s\n", cdev->name); in lpg_add_led()
1466 static int lpg_init_channels(struct lpg *lpg) in lpg_init_channels() argument
1468 const struct lpg_data *data = lpg->data; in lpg_init_channels()
1472 lpg->num_channels = data->num_channels; in lpg_init_channels()
1473 lpg->channels = devm_kcalloc(lpg->dev, data->num_channels, in lpg_init_channels()
1475 if (!lpg->channels) in lpg_init_channels()
1479 chan = &lpg->channels[i]; in lpg_init_channels()
1481 chan->lpg = lpg; in lpg_init_channels()
1487 regmap_read(lpg->map, chan->base + LPG_SUBTYPE_REG, &chan->subtype); in lpg_init_channels()
1493 static int lpg_init_triled(struct lpg *lpg) in lpg_init_triled() argument
1495 struct device_node *np = lpg->dev->of_node; in lpg_init_triled()
1499 if (!lpg->data->triled_base) in lpg_init_triled()
1502 lpg->triled_base = lpg->data->triled_base; in lpg_init_triled()
1503 lpg->triled_has_atc_ctl = lpg->data->triled_has_atc_ctl; in lpg_init_triled()
1504 lpg->triled_has_src_sel = lpg->data->triled_has_src_sel; in lpg_init_triled()
1506 if (lpg->triled_has_src_sel) { in lpg_init_triled()
1507 ret = of_property_read_u32(np, "qcom,power-source", &lpg->triled_src); in lpg_init_triled()
1508 if (ret || lpg->triled_src == 2 || lpg->triled_src > 3) in lpg_init_triled()
1509 return dev_err_probe(lpg->dev, -EINVAL, in lpg_init_triled()
1514 if (lpg->triled_has_atc_ctl) in lpg_init_triled()
1515 regmap_write(lpg->map, lpg->triled_base + TRI_LED_ATC_CTL, 0); in lpg_init_triled()
1518 if (lpg->triled_has_src_sel) in lpg_init_triled()
1519 regmap_write(lpg->map, lpg->triled_base + TRI_LED_SRC_SEL, lpg->triled_src); in lpg_init_triled()
1522 regmap_write(lpg->map, lpg->triled_base + TRI_LED_EN_CTL, 0); in lpg_init_triled()
1527 static int lpg_init_lut(struct lpg *lpg) in lpg_init_lut() argument
1529 const struct lpg_data *data = lpg->data; in lpg_init_lut()
1534 lpg->lut_size = data->lut_size; in lpg_init_lut()
1536 lpg->lut_base = data->lut_base; in lpg_init_lut()
1538 lpg->lut_bitmap = devm_bitmap_zalloc(lpg->dev, lpg->lut_size, GFP_KERNEL); in lpg_init_lut()
1539 if (!lpg->lut_bitmap) in lpg_init_lut()
1545 static int lpg_init_sdam(struct lpg *lpg) in lpg_init_sdam() argument
1550 sdam_count = of_property_count_strings(lpg->dev->of_node, "nvmem-names"); in lpg_init_sdam()
1556 /* Get the 1st SDAM device for LPG/LUT config */ in lpg_init_sdam()
1557 lpg->lpg_chan_sdam = devm_nvmem_device_get(lpg->dev, "lpg_chan_sdam"); in lpg_init_sdam()
1558 if (IS_ERR(lpg->lpg_chan_sdam)) in lpg_init_sdam()
1559 return dev_err_probe(lpg->dev, PTR_ERR(lpg->lpg_chan_sdam), in lpg_init_sdam()
1560 "Failed to get LPG chan SDAM device\n"); in lpg_init_sdam()
1564 lpg->pbs_dev = get_pbs_client_device(lpg->dev); in lpg_init_sdam()
1565 if (IS_ERR(lpg->pbs_dev)) in lpg_init_sdam()
1566 return dev_err_probe(lpg->dev, PTR_ERR(lpg->pbs_dev), in lpg_init_sdam()
1570 lpg->lut_sdam = devm_nvmem_device_get(lpg->dev, "lut_sdam"); in lpg_init_sdam()
1571 if (IS_ERR(lpg->lut_sdam)) in lpg_init_sdam()
1572 return dev_err_probe(lpg->dev, PTR_ERR(lpg->lut_sdam), in lpg_init_sdam()
1573 "Failed to get LPG LUT SDAM device\n"); in lpg_init_sdam()
1576 for (i = 0; i < lpg->num_channels; i++) { in lpg_init_sdam()
1577 struct lpg_channel *chan = &lpg->channels[i]; in lpg_init_sdam()
1580 rc = nvmem_device_write(lpg->lpg_chan_sdam, in lpg_init_sdam()
1589 rc = lpg_clear_pbs_trigger(chan->lpg, chan->lut_mask); in lpg_init_sdam()
1600 struct lpg *lpg; in lpg_probe() local
1604 lpg = devm_kzalloc(&pdev->dev, sizeof(*lpg), GFP_KERNEL); in lpg_probe()
1605 if (!lpg) in lpg_probe()
1608 lpg->data = of_device_get_match_data(&pdev->dev); in lpg_probe()
1609 if (!lpg->data) in lpg_probe()
1612 lpg->dev = &pdev->dev; in lpg_probe()
1613 mutex_init(&lpg->lock); in lpg_probe()
1615 lpg->map = dev_get_regmap(pdev->dev.parent, NULL); in lpg_probe()
1616 if (!lpg->map) in lpg_probe()
1619 ret = lpg_init_channels(lpg); in lpg_probe()
1623 ret = lpg_parse_dtest(lpg); in lpg_probe()
1627 ret = lpg_init_triled(lpg); in lpg_probe()
1631 ret = lpg_init_sdam(lpg); in lpg_probe()
1635 ret = lpg_init_lut(lpg); in lpg_probe()
1640 ret = lpg_add_led(lpg, np); in lpg_probe()
1645 for (i = 0; i < lpg->num_channels; i++) in lpg_probe()
1646 lpg_apply_dtest(&lpg->channels[i]); in lpg_probe()
1648 return lpg_add_pwm(lpg); in lpg_probe()
1821 { .compatible = "qcom,pm660l-lpg", .data = &pm660l_lpg_data },
1822 { .compatible = "qcom,pm8150b-lpg", .data = &pm8150b_lpg_data },
1823 { .compatible = "qcom,pm8150l-lpg", .data = &pm8150l_lpg_data },
1826 { .compatible = "qcom,pm8941-lpg", .data = &pm8941_lpg_data },
1827 { .compatible = "qcom,pm8994-lpg", .data = &pm8994_lpg_data },
1828 { .compatible = "qcom,pmi632-lpg", .data = &pmi632_lpg_data },
1830 { .compatible = "qcom,pmi8994-lpg", .data = &pmi8994_lpg_data },
1831 { .compatible = "qcom,pmi8998-lpg", .data = &pmi8998_lpg_data },
1832 { .compatible = "qcom,pmc8180c-lpg", .data = &pm8150l_lpg_data },
1841 .name = "qcom-spmi-lpg",
1847 MODULE_DESCRIPTION("Qualcomm LPG LED driver");