mfd: pm8xxx-pwm: Add support for pwm size of 7 bit
The existing pwm driver only supports 6 and 9bit pwm modes.
In 6 bit and 9 bit PWM modes, PWM high bank supports 12mA current
sink and 4mA current sink is not supported with PWM low bank in
these PWM podes. To support 4mA PWM current sink enable 7 bit PWM
mode and PWM low bank.
CRs-Fixed: 486318
Change-Id: I639d516196bda47346c979f5b8ae3c27fcaef104
Signed-off-by: Prasad Sodagudi <psodagud@codeaurora.org>
diff --git a/drivers/mfd/pm8xxx-pwm.c b/drivers/mfd/pm8xxx-pwm.c
index eb8320f..24fd5c1 100644
--- a/drivers/mfd/pm8xxx-pwm.c
+++ b/drivers/mfd/pm8xxx-pwm.c
@@ -35,7 +35,7 @@
*/
#define PM8XXX_LPG_V0_PWM_CHANNELS 8
#define PM8XXX_LPG_V1_PWM_CHANNELS 6
-#define PM8XXX_LPG_CTL_REGS 7
+#define PM8XXX_LPG_CTL_REGS 8
/* PM8XXX PWM */
#define SSBI_REG_ADDR_PWM1_CTRL1 0x88
@@ -66,6 +66,7 @@
#define SSBI_REG_ADDR_LPG_LUT_CFG0 0x145
#define SSBI_REG_ADDR_LPG_LUT_CFG1 0x146
#define SSBI_REG_ADDR_LPG_TEST 0x147
+#define SSBI_REG_ADDR_LPG_CTL_7 0x14D
/* LPG Control 0 */
#define PM8XXX_PWM_1KHZ_COUNT_MASK 0xF0
@@ -126,6 +127,7 @@
#define PM8XXX_PWM_PAUSE_ENABLE_HIGH 0x02
#define PM8XXX_PWM_SIZE_9_BIT 0x01
+#define PM8XXX_PWM_SIZE_7_BIT 0x04
/* LPG Control 6 */
#define PM8XXX_PWM_PAUSE_COUNT_LO_MASK 0xFC
@@ -369,17 +371,22 @@
}
static void pm8xxx_pwm_calc_period(unsigned int period_us,
- struct pm8xxx_pwm_period *period)
+ struct pwm_device *pwm)
{
int n, m, clk, div;
int best_m, best_div, best_clk;
unsigned int last_err, cur_err, min_err;
unsigned int tmp_p, period_n;
+ struct pm8xxx_pwm_period *period = &pwm->period;
+
+ if (pwm->banks == PM_PWM_BANK_LO)
+ n = 7;
+ else
+ n = 6;
/* PWM Period / N */
if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
- period_n = (period_us * NSEC_PER_USEC) >> 6;
- n = 6;
+ period_n = (period_us * NSEC_PER_USEC) >> n;
} else {
period_n = (period_us >> 9) * NSEC_PER_USEC;
n = 9;
@@ -458,6 +465,9 @@
int rc = 0;
pwm_size = (pwm->pwm_lpg_ctl[5] & PM8XXX_PWM_SIZE_9_BIT) ? 9 : 6;
+ if (pwm->period.pwm_size == 7)
+ pwm_size = 7;
+
max_pwm_value = (1 << pwm_size) - 1;
for (i = 0; i < len; i++) {
if (raw_value)
@@ -512,9 +522,16 @@
PM8XXX_LPG_PWM_PREDIVIDE_MASK | PM8XXX_LPG_PWM_M_MASK;
pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[4], mask, val);
- val = (pwm->period.pwm_size > 6) ? PM8XXX_PWM_SIZE_9_BIT : 0;
- mask = PM8XXX_PWM_SIZE_9_BIT;
- pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[5], mask, val);
+ if (pwm->period.pwm_size == 7) {
+ val = PM8XXX_PWM_SIZE_7_BIT;
+ mask = PM8XXX_PWM_SIZE_7_BIT;
+ pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[7], mask, val);
+ } else {
+ val = (pwm->period.pwm_size > 6) ?
+ PM8XXX_PWM_SIZE_9_BIT : 0;
+ mask = PM8XXX_PWM_SIZE_9_BIT;
+ pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[5], mask, val);
+ }
} else {
val = ((pwm->period.clk + 1) << PM8XXX_PWM_CLK_SEL_SHIFT)
& PM8XXX_PWM_CLK_SEL_MASK;
@@ -639,8 +656,18 @@
{
int i, rc;
+ if (end == 7) {
+ rc = pm8xxx_writeb(pwm->chip->dev->parent,
+ SSBI_REG_ADDR_LPG_CTL_7,
+ pwm->pwm_lpg_ctl[end]);
+ if (rc) {
+ pr_err("pm8xxx_writeb(): rc=%d (PWM Ctl[7])\n", rc);
+ return rc;
+ }
+ }
+
/* Write in reverse way so 0 would be the last */
- for (i = end - 1; i >= start; i--) {
+ for (i = end - 2; i >= start; i--) {
rc = pm8xxx_writeb(pwm->chip->dev->parent,
SSBI_REG_ADDR_LPG_CTL(i),
pwm->pwm_lpg_ctl[i]);
@@ -788,7 +815,7 @@
}
if (pwm->pwm_period != period_us) {
- pm8xxx_pwm_calc_period(period_us, period);
+ pm8xxx_pwm_calc_period(period_us, pwm);
pm8xxx_pwm_save_period(pwm);
pwm->pwm_period = period_us;
}
@@ -801,7 +828,7 @@
PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
pm8xxx_pwm_bank_sel(pwm);
- rc = pm8xxx_lpg_pwm_write(pwm, 1, 6);
+ rc = pm8xxx_lpg_pwm_write(pwm, 1, 7);
} else {
rc = pm8xxx_pwm_write(pwm);
}
@@ -851,7 +878,7 @@
* PWM mode.
*/
if (pwm->chip->is_pwm_enable_sync_workaround_needed)
- rc = pm8xxx_lpg_pwm_write(pwm, 3, 4);
+ rc = pm8xxx_lpg_pwm_write(pwm, 3, 5);
} else {
pm8xxx_pwm_enable(pwm);
@@ -921,7 +948,7 @@
if (pwm_chip->is_lpg_supported) {
pm8xxx_pwm_bank_sel(pwm);
- rc = pm8xxx_lpg_pwm_write(pwm, 4, 6);
+ rc = pm8xxx_lpg_pwm_write(pwm, 4, 7);
} else {
rc = pm8xxx_pwm_write(pwm);
}
@@ -965,7 +992,7 @@
pm8xxx_pwm_save(&pwm->pwm_lpg_ctl[1],
PM8XXX_PWM_BYPASS_LUT, PM8XXX_PWM_BYPASS_LUT);
pm8xxx_pwm_bank_sel(pwm);
- rc = pm8xxx_lpg_pwm_write(pwm, 1, 6);
+ rc = pm8xxx_lpg_pwm_write(pwm, 1, 7);
} else {
rc = pm8xxx_pwm_write(pwm);
}
@@ -996,7 +1023,6 @@
int idx_len, int pause_lo, int pause_hi, int flags)
{
struct pm8xxx_pwm_lut lut;
- struct pm8xxx_pwm_period *period;
int len;
int rc;
@@ -1032,7 +1058,6 @@
return -EINVAL;
}
- period = &pwm->period;
mutex_lock(&pwm->chip->pwm_mutex);
if (flags & PM_PWM_BANK_HI)
@@ -1052,7 +1077,7 @@
}
if (pwm->pwm_period != period_us) {
- pm8xxx_pwm_calc_period(period_us, period);
+ pm8xxx_pwm_calc_period(period_us, pwm);
pm8xxx_pwm_save_period(pwm);
pwm->pwm_period = period_us;
}