Merge "pwm: qti-lpg: Read tick duration via device tree"
This commit is contained in:
commit
af2d4f76fd
@ -134,6 +134,12 @@ enum lpg_src {
|
||||
PWM_VALUE,
|
||||
};
|
||||
|
||||
enum ppg_num_nvmems {
|
||||
PPG_NO_NVMEMS,
|
||||
PPG_NVMEMS_1, /* A single nvmem for both LUT and LPG channel config */
|
||||
PPG_NVMEMS_2, /* Two separate nvmems for LUT and LPG channel config */
|
||||
};
|
||||
|
||||
static const int pwm_size[NUM_PWM_SIZE] = {6, 9};
|
||||
static const int clk_freq_hz[NUM_PWM_CLK] = {1024, 32768, 19200000};
|
||||
static const int clk_prediv[NUM_CLK_PREDIV] = {1, 3, 5, 6};
|
||||
@ -164,8 +170,10 @@ struct lpg_pwm_config {
|
||||
struct qpnp_lpg_lut {
|
||||
struct qpnp_lpg_chip *chip;
|
||||
struct mutex lock;
|
||||
enum ppg_num_nvmems nvmem_count;
|
||||
u32 reg_base;
|
||||
u32 *pattern; /* patterns in percentage */
|
||||
u32 ramp_step_tick_us;
|
||||
};
|
||||
|
||||
struct qpnp_lpg_channel {
|
||||
@ -191,7 +199,8 @@ struct qpnp_lpg_chip {
|
||||
struct qpnp_lpg_lut *lut;
|
||||
struct mutex bus_lock;
|
||||
u32 *lpg_group;
|
||||
struct nvmem_device *sdam_nvmem;
|
||||
struct nvmem_device *lpg_chan_nvmem;
|
||||
struct nvmem_device *lut_nvmem;
|
||||
struct device_node *pbs_dev_node;
|
||||
u32 num_lpgs;
|
||||
unsigned long pbs_en_bitmap;
|
||||
@ -275,12 +284,13 @@ static int qpnp_lut_masked_write(struct qpnp_lpg_lut *lut,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int qpnp_sdam_write(struct qpnp_lpg_chip *chip, u16 addr, u8 val)
|
||||
static int qpnp_lpg_chan_nvmem_write(struct qpnp_lpg_chip *chip, u16 addr,
|
||||
u8 val)
|
||||
{
|
||||
int rc;
|
||||
|
||||
mutex_lock(&chip->bus_lock);
|
||||
rc = nvmem_device_write(chip->sdam_nvmem, addr, 1, &val);
|
||||
rc = nvmem_device_write(chip->lpg_chan_nvmem, addr, 1, &val);
|
||||
if (rc < 0)
|
||||
dev_err(chip->dev, "write SDAM add 0x%x failed, rc=%d\n",
|
||||
addr, rc);
|
||||
@ -296,7 +306,7 @@ static int qpnp_lpg_sdam_write(struct qpnp_lpg_channel *lpg, u16 addr, u8 val)
|
||||
int rc;
|
||||
|
||||
mutex_lock(&chip->bus_lock);
|
||||
rc = nvmem_device_write(chip->sdam_nvmem,
|
||||
rc = nvmem_device_write(chip->lpg_chan_nvmem,
|
||||
lpg->lpg_sdam_base + addr, 1, &val);
|
||||
if (rc < 0)
|
||||
dev_err(chip->dev, "write SDAM add 0x%x failed, rc=%d\n",
|
||||
@ -316,7 +326,7 @@ static int qpnp_lpg_sdam_masked_write(struct qpnp_lpg_channel *lpg,
|
||||
|
||||
mutex_lock(&chip->bus_lock);
|
||||
|
||||
rc = nvmem_device_read(chip->sdam_nvmem,
|
||||
rc = nvmem_device_read(chip->lpg_chan_nvmem,
|
||||
lpg->lpg_sdam_base + addr, 1, &tmp);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Read SDAM addr %d failed, rc=%d\n",
|
||||
@ -326,7 +336,7 @@ static int qpnp_lpg_sdam_masked_write(struct qpnp_lpg_channel *lpg,
|
||||
|
||||
tmp = tmp & ~mask;
|
||||
tmp |= val & mask;
|
||||
rc = nvmem_device_write(chip->sdam_nvmem,
|
||||
rc = nvmem_device_write(chip->lpg_chan_nvmem,
|
||||
lpg->lpg_sdam_base + addr, 1, &tmp);
|
||||
if (rc < 0)
|
||||
dev_err(chip->dev, "write SDAM addr %d failed, rc=%d\n",
|
||||
@ -348,7 +358,7 @@ static int qpnp_lut_sdam_write(struct qpnp_lpg_lut *lut,
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&chip->bus_lock);
|
||||
rc = nvmem_device_write(chip->sdam_nvmem,
|
||||
rc = nvmem_device_write(chip->lut_nvmem,
|
||||
lut->reg_base + addr, length, val);
|
||||
if (rc < 0)
|
||||
dev_err(chip->dev, "write SDAM addr %d failed, rc=%d\n",
|
||||
@ -513,6 +523,18 @@ unlock:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define SDAM_START_BASE 0x40
|
||||
static u8 qpnp_lpg_get_sdam_lut_idx(struct qpnp_lpg_channel *lpg, u8 idx)
|
||||
{
|
||||
struct qpnp_lpg_chip *chip = lpg->chip;
|
||||
u8 val = idx;
|
||||
|
||||
if (chip->lut->nvmem_count == PPG_NVMEMS_2)
|
||||
val += (chip->lut->reg_base - SDAM_START_BASE);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int qpnp_lpg_set_sdam_ramp_config(struct qpnp_lpg_channel *lpg)
|
||||
{
|
||||
struct lpg_ramp_config *ramp = &lpg->ramp_config;
|
||||
@ -529,12 +551,12 @@ static int qpnp_lpg_set_sdam_ramp_config(struct qpnp_lpg_channel *lpg)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Set ramp step duration, one WAIT_TICK is 7.8ms */
|
||||
val = (ramp->step_ms * 1000 / 7800) & 0xff;
|
||||
/* Set ramp step duration, in ticks */
|
||||
val = (ramp->step_ms * 1000 / lpg->chip->lut->ramp_step_tick_us) & 0xff;
|
||||
if (val > 0)
|
||||
val--;
|
||||
addr = SDAM_REG_RAMP_STEP_DURATION;
|
||||
rc = qpnp_sdam_write(lpg->chip, addr, val);
|
||||
rc = qpnp_lpg_chan_nvmem_write(lpg->chip, addr, val);
|
||||
if (rc < 0) {
|
||||
dev_err(lpg->chip->dev, "Write SDAM_REG_RAMP_STEP_DURATION failed, rc=%d\n",
|
||||
rc);
|
||||
@ -542,15 +564,16 @@ static int qpnp_lpg_set_sdam_ramp_config(struct qpnp_lpg_channel *lpg)
|
||||
}
|
||||
|
||||
/* Set hi_idx and lo_idx */
|
||||
rc = qpnp_lpg_sdam_write(lpg, SDAM_END_INDEX_OFFSET, ramp->hi_idx);
|
||||
val = qpnp_lpg_get_sdam_lut_idx(lpg, ramp->hi_idx);
|
||||
rc = qpnp_lpg_sdam_write(lpg, SDAM_END_INDEX_OFFSET, val);
|
||||
if (rc < 0) {
|
||||
dev_err(lpg->chip->dev, "Write SDAM_REG_END_INDEX failed, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = qpnp_lpg_sdam_write(lpg, SDAM_START_INDEX_OFFSET,
|
||||
ramp->lo_idx);
|
||||
val = qpnp_lpg_get_sdam_lut_idx(lpg, ramp->lo_idx);
|
||||
rc = qpnp_lpg_sdam_write(lpg, SDAM_START_INDEX_OFFSET, val);
|
||||
if (rc < 0) {
|
||||
dev_err(lpg->chip->dev, "Write SDAM_REG_START_INDEX failed, rc=%d\n",
|
||||
rc);
|
||||
@ -880,6 +903,63 @@ static int qpnp_lpg_pwm_config(struct pwm_chip *pwm_chip,
|
||||
return qpnp_lpg_config(lpg, duty_ns, period_ns);
|
||||
}
|
||||
|
||||
#define SDAM_PBS_TRIG_SET 0xe5
|
||||
#define SDAM_PBS_TRIG_CLR 0xe6
|
||||
static int qpnp_lpg_clear_pbs_trigger(struct qpnp_lpg_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = qpnp_lpg_chan_nvmem_write(chip,
|
||||
SDAM_REG_PBS_SEQ_EN, 0);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Write SDAM_REG_PBS_SEQ_EN failed, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (chip->lut->nvmem_count == PPG_NVMEMS_2) {
|
||||
rc = qpnp_lpg_chan_nvmem_write(chip, SDAM_PBS_TRIG_CLR,
|
||||
PBS_SW_TRG_BIT);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Failed to fire PBS seq, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qpnp_lpg_set_pbs_trigger(struct qpnp_lpg_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = qpnp_lpg_chan_nvmem_write(chip,
|
||||
SDAM_REG_PBS_SEQ_EN, PBS_SW_TRG_BIT);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Write SDAM_REG_PBS_SEQ_EN failed, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (chip->lut->nvmem_count == PPG_NVMEMS_1) {
|
||||
if (!chip->pbs_dev_node) {
|
||||
dev_err(chip->dev, "PBS device unavailable\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
rc = qpnp_pbs_trigger_event(chip->pbs_dev_node,
|
||||
PBS_SW_TRG_BIT);
|
||||
} else {
|
||||
rc = qpnp_lpg_chan_nvmem_write(chip, SDAM_PBS_TRIG_SET,
|
||||
PBS_SW_TRG_BIT);
|
||||
}
|
||||
|
||||
if (rc < 0)
|
||||
dev_err(chip->dev, "Failed to trigger PBS, rc=%d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int qpnp_lpg_pbs_trigger_enable(struct qpnp_lpg_channel *lpg, bool en)
|
||||
{
|
||||
struct qpnp_lpg_chip *chip = lpg->chip;
|
||||
@ -887,32 +967,17 @@ static int qpnp_lpg_pbs_trigger_enable(struct qpnp_lpg_channel *lpg, bool en)
|
||||
|
||||
if (en) {
|
||||
if (chip->pbs_en_bitmap == 0) {
|
||||
rc = qpnp_sdam_write(chip, SDAM_REG_PBS_SEQ_EN,
|
||||
PBS_SW_TRG_BIT);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Write SDAM_REG_PBS_SEQ_EN failed, rc=%d\n",
|
||||
rc);
|
||||
rc = qpnp_lpg_set_pbs_trigger(chip);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = qpnp_pbs_trigger_event(chip->pbs_dev_node,
|
||||
PBS_SW_TRG_BIT);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Failed to trigger PBS, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
set_bit(lpg->lpg_idx, &chip->pbs_en_bitmap);
|
||||
} else {
|
||||
clear_bit(lpg->lpg_idx, &chip->pbs_en_bitmap);
|
||||
if (chip->pbs_en_bitmap == 0) {
|
||||
rc = qpnp_sdam_write(chip, SDAM_REG_PBS_SEQ_EN, 0);
|
||||
if (rc < 0) {
|
||||
dev_err(chip->dev, "Write SDAM_REG_PBS_SEQ_EN failed, rc=%d\n",
|
||||
rc);
|
||||
rc = qpnp_lpg_clear_pbs_trigger(chip);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1449,6 +1514,43 @@ static bool lut_is_defined(struct qpnp_lpg_chip *chip, const __be32 **addr)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int qpnp_lpg_get_nvmem_dt(struct qpnp_lpg_chip *chip)
|
||||
{
|
||||
int rc = 0;
|
||||
struct nvmem_device *ppg_nv, *lut_nv, *lpg_nv;
|
||||
|
||||
/* Ensure backward compatibility */
|
||||
ppg_nv = devm_nvmem_device_get(chip->dev, "ppg_sdam");
|
||||
if (IS_ERR(ppg_nv)) {
|
||||
lut_nv = devm_nvmem_device_get(chip->dev, "lut_sdam");
|
||||
if (IS_ERR(lut_nv)) {
|
||||
rc = PTR_ERR(lut_nv);
|
||||
goto err;
|
||||
}
|
||||
|
||||
lpg_nv = devm_nvmem_device_get(chip->dev, "lpg_chan_sdam");
|
||||
if (IS_ERR(lpg_nv)) {
|
||||
rc = PTR_ERR(lpg_nv);
|
||||
goto err;
|
||||
}
|
||||
|
||||
chip->lut_nvmem = lut_nv;
|
||||
chip->lpg_chan_nvmem = lpg_nv;
|
||||
chip->lut->nvmem_count = PPG_NVMEMS_2;
|
||||
} else {
|
||||
chip->lut_nvmem = chip->lpg_chan_nvmem = ppg_nv;
|
||||
chip->lut->nvmem_count = PPG_NVMEMS_1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
if (rc != -EPROBE_DEFER)
|
||||
dev_err(chip->dev, "Failed to get nvmem device, rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define DEFAULT_TICK_DURATION_US 7800
|
||||
static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip)
|
||||
{
|
||||
int rc = 0, i;
|
||||
@ -1483,21 +1585,20 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip)
|
||||
if (!chip->lut)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->sdam_nvmem = devm_nvmem_device_get(chip->dev, "ppg_sdam");
|
||||
if (IS_ERR_OR_NULL(chip->sdam_nvmem)) {
|
||||
rc = PTR_ERR(chip->sdam_nvmem);
|
||||
if (rc != -EPROBE_DEFER)
|
||||
dev_err(chip->dev, "Failed to get nvmem device, rc=%d\n",
|
||||
rc);
|
||||
rc = qpnp_lpg_get_nvmem_dt(chip);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
chip->use_sdam = true;
|
||||
chip->pbs_dev_node = of_parse_phandle(chip->dev->of_node,
|
||||
"qcom,pbs-client", 0);
|
||||
if (!chip->pbs_dev_node) {
|
||||
dev_err(chip->dev, "Missing qcom,pbs-client property\n");
|
||||
return -EINVAL;
|
||||
if (of_find_property(chip->dev->of_node, "qcom,pbs-client",
|
||||
NULL)) {
|
||||
chip->pbs_dev_node = of_parse_phandle(
|
||||
chip->dev->of_node,
|
||||
"qcom,pbs-client", 0);
|
||||
if (!chip->pbs_dev_node) {
|
||||
dev_err(chip->dev, "Missing qcom,pbs-client property\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(chip->dev->of_node,
|
||||
@ -1509,6 +1610,10 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip)
|
||||
return rc;
|
||||
}
|
||||
|
||||
chip->lut->ramp_step_tick_us = DEFAULT_TICK_DURATION_US;
|
||||
of_property_read_u32(chip->dev->of_node, "qcom,tick-period-us",
|
||||
&chip->lut->ramp_step_tick_us);
|
||||
|
||||
rc = qpnp_lpg_parse_pattern_dt(chip, SDAM_LUT_COUNT_MAX);
|
||||
if (rc < 0) {
|
||||
of_node_put(chip->pbs_dev_node);
|
||||
@ -1616,6 +1721,7 @@ static int qpnp_lpg_remove(struct platform_device *pdev)
|
||||
struct qpnp_lpg_chip *chip = dev_get_drvdata(&pdev->dev);
|
||||
int rc = 0;
|
||||
|
||||
of_node_put(chip->pbs_dev_node);
|
||||
rc = pwmchip_remove(&chip->pwm_chip);
|
||||
if (rc < 0)
|
||||
dev_err(chip->dev, "Remove pwmchip failed, rc=%d\n", rc);
|
||||
|
Loading…
Reference in New Issue
Block a user