pwm: qpnp-pwm: add api for synchronous enable of pwms
Change-Id: Ibe4d8f8f8c9dbb89434cd633a049bd9e216af6f4 Signed-off-by: Pranav Vashi <neobuddy89@gmail.com>
This commit is contained in:
parent
33152bb4c7
commit
c3b7b440aa
2 changed files with 130 additions and 0 deletions
|
@ -1139,6 +1139,88 @@ static int qpnp_lpg_configure_lut_state(struct qpnp_pwm_chip *chip,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int qpnp_lpg_configure_lut_states(struct qpnp_pwm_chip **chips,
|
||||
int num, enum qpnp_lut_state state)
|
||||
{
|
||||
struct qpnp_pwm_chip *chip;
|
||||
struct qpnp_lpg_config *lpg_config;
|
||||
u8 value1, value2, mask1, mask2;
|
||||
u8 *reg1, *reg2;
|
||||
u16 addr, addr1;
|
||||
int rc, i;
|
||||
bool test_enable;
|
||||
u8 ramp_en = 0, ramp_mask = 0;
|
||||
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
chip = chips[i];
|
||||
lpg_config = &chip->lpg_config;
|
||||
value1 = chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL];
|
||||
reg1 = &chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL];
|
||||
reg2 = &chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL];
|
||||
mask2 = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
|
||||
QPNP_PWM_SRC_SELECT_MASK | QPNP_PWM_EN_RAMP_GEN_MASK;
|
||||
if (chip->sub_type != QPNP_LPG_S_CHAN_SUB_TYPE)
|
||||
mask2 |= QPNP_EN_PWM_OUTPUT_MASK;
|
||||
|
||||
if (chip->sub_type == QPNP_LPG_CHAN_SUB_TYPE
|
||||
&& chip->revision == QPNP_LPG_REVISION_0) {
|
||||
if (state == QPNP_LUT_ENABLE) {
|
||||
QPNP_ENABLE_LUT_V0(value1);
|
||||
value2 = QPNP_ENABLE_LPG_MODE(chip);
|
||||
} else {
|
||||
QPNP_DISABLE_LUT_V0(value1);
|
||||
value2 = QPNP_DISABLE_LPG_MODE(chip);
|
||||
}
|
||||
mask1 = QPNP_RAMP_START_MASK;
|
||||
addr1 = SPMI_LPG_REG_ADDR(lpg_config->base_addr,
|
||||
QPNP_RAMP_CONTROL);
|
||||
} else if ((chip->sub_type == QPNP_LPG_CHAN_SUB_TYPE
|
||||
&& chip->revision == QPNP_LPG_REVISION_1)
|
||||
|| chip->sub_type == QPNP_LPG_S_CHAN_SUB_TYPE) {
|
||||
if (state == QPNP_LUT_ENABLE) {
|
||||
QPNP_ENABLE_LUT_V1(value1,
|
||||
lpg_config->lut_config.ramp_index);
|
||||
value2 = QPNP_ENABLE_LPG_MODE(chip);
|
||||
} else {
|
||||
value2 = QPNP_DISABLE_LPG_MODE(chip);
|
||||
}
|
||||
mask1 = value1;
|
||||
addr1 = lpg_config->lut_base_addr +
|
||||
SPMI_LPG_REV1_RAMP_CONTROL_OFFSET;
|
||||
} else {
|
||||
pr_err("Unsupported LPG subtype 0x%02x, revision 0x%02x\n",
|
||||
chip->sub_type, chip->revision);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
addr = SPMI_LPG_REG_ADDR(lpg_config->base_addr,
|
||||
QPNP_ENABLE_CONTROL);
|
||||
|
||||
if (chip->in_test_mode) {
|
||||
test_enable = (state == QPNP_LUT_ENABLE) ? 1 : 0;
|
||||
rc = qpnp_dtest_config(chip, test_enable);
|
||||
if (rc)
|
||||
pr_err("Failed to configure TEST mode\n");
|
||||
}
|
||||
|
||||
rc = qpnp_lpg_save_and_write(value2, mask2, reg2,
|
||||
addr, 1, chip);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
ramp_en |= value1;
|
||||
ramp_mask |= mask1;
|
||||
}
|
||||
|
||||
if (state == QPNP_LUT_ENABLE
|
||||
|| (chip->sub_type == QPNP_LPG_CHAN_SUB_TYPE
|
||||
&& chip->revision == QPNP_LPG_REVISION_0))
|
||||
rc = qpnp_lpg_save_and_write(ramp_en, ramp_mask, reg1,
|
||||
addr1, 1, chip);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int qpnp_enable_pwm_mode(struct qpnp_pwm_chip *chip)
|
||||
{
|
||||
if (chip->pwm_config.supported_sizes == QPNP_PWM_SIZE_7_8_BIT)
|
||||
|
@ -1443,6 +1525,49 @@ static int qpnp_pwm_enable(struct pwm_chip *pwm_chip,
|
|||
return rc;
|
||||
}
|
||||
|
||||
int pwm_enable_synchronized(struct pwm_device **pwms, size_t num)
|
||||
{
|
||||
unsigned long *flags;
|
||||
struct qpnp_pwm_chip **chips;
|
||||
int rc = 0, i;
|
||||
|
||||
if (pwms == NULL || IS_ERR(pwms) || num == 0) {
|
||||
pr_err("Invalid pwm handle or idx_len=0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
flags = kzalloc(sizeof(unsigned long) * num, GFP_KERNEL);
|
||||
if (!flags)
|
||||
return -ENOMEM;
|
||||
|
||||
chips = kzalloc(sizeof(struct qpnp_pwm_chip *) * num, GFP_KERNEL);
|
||||
if (!chips) {
|
||||
kfree(flags);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
chips[i] = qpnp_pwm_from_pwm_dev(pwms[i]);
|
||||
if (chips[i] == NULL) {
|
||||
rc = -EINVAL;
|
||||
goto err_failed;
|
||||
}
|
||||
spin_lock_irqsave(&chips[i]->lpg_lock, flags[i]);
|
||||
}
|
||||
|
||||
rc = qpnp_lpg_configure_lut_states(chips, num, QPNP_LUT_ENABLE);
|
||||
|
||||
err_failed:
|
||||
while(i > 0) {
|
||||
spin_unlock_irqrestore(&chips[i - 1]->lpg_lock, flags[i - 1]);
|
||||
i--;
|
||||
}
|
||||
kfree(flags);
|
||||
kfree(chips);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwm_enable_synchronized);
|
||||
|
||||
/**
|
||||
* qpnp_pwm_disable - stop a PWM output toggling
|
||||
* @pwm_chip: the PWM chip
|
||||
|
|
|
@ -185,6 +185,11 @@ static inline int pwm_config_us(struct pwm_device *pwm,
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* synchronized enable of multiple pwm instances
|
||||
*/
|
||||
int pwm_enable_synchronized(struct pwm_device **pwms, size_t num);
|
||||
|
||||
/* Standard APIs supported */
|
||||
/*
|
||||
* pwm_request - request a PWM device
|
||||
|
|
Loading…
Add table
Reference in a new issue