Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 93824d79 authored by Fenglin Wu's avatar Fenglin Wu
Browse files

pwm: qti-lpg: Correct PWM_SIZE setting for PWM module



PWM module with subtype value 0xb has different register mapping on
PWM_SIZE with LPG module, so read the subtype and apply the PWM_SIZE
setting according to different subtype values.

Change-Id: I5222de22345784399c113656414811cc7d6ec47b
Signed-off-by: default avatarFenglin Wu <fenglinw@codeaurora.org>
parent be5c1d18
Loading
Loading
Loading
Loading
+50 −9
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@

#define REG_SIZE_PER_LPG	0x100

#define REG_LPG_PERPH_SUBTYPE		0x05
#define REG_LPG_PWM_SIZE_CLK		0x41
#define REG_LPG_PWM_FREQ_PREDIV_CLK	0x42
#define REG_LPG_PWM_TYPE_CONFIG		0x43
@@ -36,9 +37,15 @@
#define REG_LPG_ENABLE_CONTROL		0x46
#define REG_LPG_PWM_SYNC		0x47

/* REG_LPG_PERPH_SUBTYPE */
#define SUBTYPE_PWM			0x0b
#define SUBTYPE_LPG_LITE		0x11

/* REG_LPG_PWM_SIZE_CLK */
#define LPG_PWM_SIZE_MASK		BIT(4)
#define LPG_PWM_SIZE_SHIFT		4
#define LPG_PWM_SIZE_MASK_LPG		BIT(4)
#define LPG_PWM_SIZE_MASK_PWM		BIT(2)
#define LPG_PWM_SIZE_SHIFT_LPG		4
#define LPG_PWM_SIZE_SHIFT_PWM		2
#define LPG_PWM_CLK_FREQ_SEL_MASK	GENMASK(1, 0)

/* REG_LPG_PWM_FREQ_PREDIV_CLK */
@@ -95,6 +102,7 @@ struct qpnp_lpg_channel {
	u32				lpg_idx;
	u32				reg_base;
	u8				src_sel;
	u8				subtype;
	int				current_period_ns;
	int				current_duty_ns;
};
@@ -108,6 +116,23 @@ struct qpnp_lpg_chip {
	u32			num_lpgs;
};

static int qpnp_lpg_read(struct qpnp_lpg_channel *lpg, u16 addr, u8 *val)
{
	int rc;
	unsigned int tmp;

	mutex_lock(&lpg->chip->bus_lock);
	rc = regmap_read(lpg->chip->regmap, lpg->reg_base + addr, &tmp);
	if (rc < 0)
		dev_err(lpg->chip->dev, "Read addr 0x%x failed, rc=%d\n",
				lpg->reg_base + addr, rc);
	else
		*val = (u8)tmp;
	mutex_unlock(&lpg->chip->bus_lock);

	return rc;
}

static int qpnp_lpg_write(struct qpnp_lpg_channel *lpg, u16 addr, u8 val)
{
	int rc;
@@ -169,7 +194,7 @@ static int __find_index_in_array(int member, const int array[], int length)
static int qpnp_lpg_set_pwm_config(struct qpnp_lpg_channel *lpg)
{
	int rc;
	u8 val, mask;
	u8 val, mask, shift;
	int pwm_size_idx, pwm_clk_idx, prediv_idx, clk_exp_idx;

	pwm_size_idx = __find_index_in_array(lpg->pwm_config.pwm_size,
@@ -187,8 +212,16 @@ static int qpnp_lpg_set_pwm_config(struct qpnp_lpg_channel *lpg)

	/* pwm_clk_idx is 1 bit lower than the register value */
	pwm_clk_idx += 1;
	val = pwm_size_idx << LPG_PWM_SIZE_SHIFT | pwm_clk_idx;
	mask = LPG_PWM_SIZE_MASK | LPG_PWM_CLK_FREQ_SEL_MASK;
	if (lpg->subtype == SUBTYPE_PWM) {
		shift = LPG_PWM_SIZE_SHIFT_PWM;
		mask = LPG_PWM_SIZE_MASK_PWM;
	} else {
		shift = LPG_PWM_SIZE_SHIFT_LPG;
		mask = LPG_PWM_SIZE_MASK_LPG;
	}

	val = pwm_size_idx << shift | pwm_clk_idx;
	mask |= LPG_PWM_CLK_FREQ_SEL_MASK;
	rc = qpnp_lpg_masked_write(lpg, REG_LPG_PWM_SIZE_CLK, mask, val);
	if (rc < 0) {
		dev_err(lpg->chip->dev, "Write LPG_PWM_SIZE_CLK failed, rc=%d\n",
@@ -490,6 +523,12 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip)
		chip->lpgs[i].lpg_idx = i;
		chip->lpgs[i].reg_base = base + i * REG_SIZE_PER_LPG;
		chip->lpgs[i].src_sel = PWM_OUTPUT;
		rc = qpnp_lpg_read(&chip->lpgs[i], REG_LPG_PERPH_SUBTYPE,
				&chip->lpgs[i].subtype);
		if (rc < 0) {
			dev_err(chip->dev, "Read subtype failed, rc=%d\n", rc);
			return rc;
		}
	}

	return rc;
@@ -511,16 +550,15 @@ static int qpnp_lpg_probe(struct platform_device *pdev)
		return -EINVAL;
	}

	mutex_init(&chip->bus_lock);
	rc = qpnp_lpg_parse_dt(chip);
	if (rc < 0) {
		dev_err(chip->dev, "Devicetree properties parsing failed, rc=%d\n",
				rc);
		return rc;
		goto destroy;
	}

	dev_set_drvdata(chip->dev, chip);

	mutex_init(&chip->bus_lock);
	chip->pwm_chip.dev = chip->dev;
	chip->pwm_chip.base = -1;
	chip->pwm_chip.npwm = chip->num_lpgs;
@@ -529,9 +567,12 @@ static int qpnp_lpg_probe(struct platform_device *pdev)
	rc = pwmchip_add(&chip->pwm_chip);
	if (rc < 0) {
		dev_err(chip->dev, "Add pwmchip failed, rc=%d\n", rc);
		mutex_destroy(&chip->bus_lock);
		goto destroy;
	}

	return 0;
destroy:
	mutex_destroy(&chip->bus_lock);
	return rc;
}