mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 04:31:50 +00:00
pwm: mtk-disp: Implement atomic API .apply()
Switch the driver to support the .apply() method. Signed-off-by: Jitao Shi <jitao.shi@mediatek.com> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
This commit is contained in:
parent
d7a4e58258
commit
888a623db5
@ -47,6 +47,7 @@ struct mtk_disp_pwm {
|
||||
struct clk *clk_main;
|
||||
struct clk *clk_mm;
|
||||
void __iomem *base;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
static inline struct mtk_disp_pwm *to_mtk_disp_pwm(struct pwm_chip *chip)
|
||||
@ -66,25 +67,45 @@ static void mtk_disp_pwm_update_bits(struct mtk_disp_pwm *mdp, u32 offset,
|
||||
writel(value, address);
|
||||
}
|
||||
|
||||
static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
int duty_ns, int period_ns)
|
||||
static int mtk_disp_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
|
||||
u32 clk_div, period, high_width, value;
|
||||
u64 div, rate;
|
||||
int err;
|
||||
|
||||
err = clk_prepare_enable(mdp->clk_main);
|
||||
if (err < 0) {
|
||||
dev_err(chip->dev, "Can't enable mdp->clk_main: %pe\n", ERR_PTR(err));
|
||||
return err;
|
||||
if (state->polarity != PWM_POLARITY_NORMAL)
|
||||
return -EINVAL;
|
||||
|
||||
if (!state->enabled) {
|
||||
mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
|
||||
0x0);
|
||||
|
||||
if (mdp->enabled) {
|
||||
clk_disable_unprepare(mdp->clk_mm);
|
||||
clk_disable_unprepare(mdp->clk_main);
|
||||
}
|
||||
|
||||
mdp->enabled = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(mdp->clk_mm);
|
||||
if (err < 0) {
|
||||
dev_err(chip->dev, "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(err));
|
||||
clk_disable_unprepare(mdp->clk_main);
|
||||
return err;
|
||||
if (!mdp->enabled) {
|
||||
err = clk_prepare_enable(mdp->clk_main);
|
||||
if (err < 0) {
|
||||
dev_err(chip->dev, "Can't enable mdp->clk_main: %pe\n",
|
||||
ERR_PTR(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(mdp->clk_mm);
|
||||
if (err < 0) {
|
||||
dev_err(chip->dev, "Can't enable mdp->clk_mm: %pe\n",
|
||||
ERR_PTR(err));
|
||||
clk_disable_unprepare(mdp->clk_main);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -98,20 +119,22 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
* high_width = (PWM_CLK_RATE * duty_ns) / (10^9 * (clk_div + 1))
|
||||
*/
|
||||
rate = clk_get_rate(mdp->clk_main);
|
||||
clk_div = div_u64(rate * period_ns, NSEC_PER_SEC) >>
|
||||
clk_div = div_u64(rate * state->period, NSEC_PER_SEC) >>
|
||||
PWM_PERIOD_BIT_WIDTH;
|
||||
if (clk_div > PWM_CLKDIV_MAX) {
|
||||
clk_disable_unprepare(mdp->clk_mm);
|
||||
clk_disable_unprepare(mdp->clk_main);
|
||||
if (!mdp->enabled) {
|
||||
clk_disable_unprepare(mdp->clk_mm);
|
||||
clk_disable_unprepare(mdp->clk_main);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
div = NSEC_PER_SEC * (clk_div + 1);
|
||||
period = div64_u64(rate * period_ns, div);
|
||||
period = div64_u64(rate * state->period, div);
|
||||
if (period > 0)
|
||||
period--;
|
||||
|
||||
high_width = div64_u64(rate * duty_ns, div);
|
||||
high_width = div64_u64(rate * state->duty_cycle, div);
|
||||
value = period | (high_width << PWM_HIGH_WIDTH_SHIFT);
|
||||
|
||||
mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
|
||||
@ -141,51 +164,15 @@ static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
mdp->data->con0_sel);
|
||||
}
|
||||
|
||||
clk_disable_unprepare(mdp->clk_mm);
|
||||
clk_disable_unprepare(mdp->clk_main);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
|
||||
int err;
|
||||
|
||||
err = clk_prepare_enable(mdp->clk_main);
|
||||
if (err < 0) {
|
||||
dev_err(chip->dev, "Can't enable mdp->clk_main: %pe\n", ERR_PTR(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(mdp->clk_mm);
|
||||
if (err < 0) {
|
||||
dev_err(chip->dev, "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(err));
|
||||
clk_disable_unprepare(mdp->clk_main);
|
||||
return err;
|
||||
}
|
||||
|
||||
mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
|
||||
mdp->data->enable_mask);
|
||||
mdp->enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
|
||||
|
||||
mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
|
||||
0x0);
|
||||
|
||||
clk_disable_unprepare(mdp->clk_mm);
|
||||
clk_disable_unprepare(mdp->clk_main);
|
||||
}
|
||||
|
||||
static const struct pwm_ops mtk_disp_pwm_ops = {
|
||||
.config = mtk_disp_pwm_config,
|
||||
.enable = mtk_disp_pwm_enable,
|
||||
.disable = mtk_disp_pwm_disable,
|
||||
.apply = mtk_disp_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user