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

Commit 7d8d05d1 authored by Boris Brezillon's avatar Boris Brezillon Committed by Alexandre Belloni
Browse files

misc: atmel_tclib: get and use slow clock



Commit dca1a4b5 ("clk: at91: keep slow clk enabled to prevent system
hang") added a workaround for the slow clock as it is not properly handled
by its users.

Get and use the slow clock as it is necessary for the timer counters.

Signed-off-by: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@free-electrons.com>
Acked-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: default avatarDaniel Lezcano <daniel.lezcano@linaro.org>
Acked-by: default avatarThierry Reding <thierry.reding@gmail.com>
parent eed9fb9d
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -193,10 +193,17 @@ static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
	struct clk *t2_clk = tc->clk[2];
	int irq = tc->irq[2];

	ret = clk_prepare_enable(tc->slow_clk);
	if (ret)
		return ret;

	/* try to enable t2 clk to avoid future errors in mode change */
	ret = clk_prepare_enable(t2_clk);
	if (ret)
	if (ret) {
		clk_disable_unprepare(tc->slow_clk);
		return ret;
	}

	clk_disable(t2_clk);

	clkevt.regs = tc->regs;
@@ -209,6 +216,7 @@ static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
	ret = request_irq(irq, ch2_irq, IRQF_TIMER, "tc_clkevt", &clkevt);
	if (ret) {
		clk_unprepare(t2_clk);
		clk_disable_unprepare(tc->slow_clk);
		return ret;
	}

+4 −0
Original line number Diff line number Diff line
@@ -125,6 +125,10 @@ static int __init tc_probe(struct platform_device *pdev)
	if (IS_ERR(clk))
		return PTR_ERR(clk);

	tc->slow_clk = devm_clk_get(&pdev->dev, "slow_clk");
	if (IS_ERR(tc->slow_clk))
		return PTR_ERR(tc->slow_clk);

	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	tc->regs = devm_ioremap_resource(&pdev->dev, r);
	if (IS_ERR(tc->regs))
+19 −7
Original line number Diff line number Diff line
@@ -305,7 +305,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
	 */
	if (i == 5) {
		i = slowclk;
		rate = 32768;
		rate = clk_get_rate(tc->slow_clk);
		min = div_u64(NSEC_PER_SEC, rate);
		max = min << tc->tcb_config->counter_width;

@@ -387,9 +387,9 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)

	tcbpwm = devm_kzalloc(&pdev->dev, sizeof(*tcbpwm), GFP_KERNEL);
	if (tcbpwm == NULL) {
		atmel_tc_free(tc);
		err = -ENOMEM;
		dev_err(&pdev->dev, "failed to allocate memory\n");
		return -ENOMEM;
		goto err_free_tc;
	}

	tcbpwm->chip.dev = &pdev->dev;
@@ -400,17 +400,27 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
	tcbpwm->chip.npwm = NPWM;
	tcbpwm->tc = tc;

	err = clk_prepare_enable(tc->slow_clk);
	if (err)
		goto err_free_tc;

	spin_lock_init(&tcbpwm->lock);

	err = pwmchip_add(&tcbpwm->chip);
	if (err < 0) {
		atmel_tc_free(tc);
		return err;
	}
	if (err < 0)
		goto err_disable_clk;

	platform_set_drvdata(pdev, tcbpwm);

	return 0;

err_disable_clk:
	clk_disable_unprepare(tcbpwm->tc->slow_clk);

err_free_tc:
	atmel_tc_free(tc);

	return err;
}

static int atmel_tcb_pwm_remove(struct platform_device *pdev)
@@ -418,6 +428,8 @@ static int atmel_tcb_pwm_remove(struct platform_device *pdev)
	struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev);
	int err;

	clk_disable_unprepare(tcbpwm->tc->slow_clk);

	err = pwmchip_remove(&tcbpwm->chip);
	if (err < 0)
		return err;
+1 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ struct atmel_tc {
	const struct atmel_tcb_config *tcb_config;
	int			irq[3];
	struct clk		*clk[3];
	struct clk		*slow_clk;
	struct list_head	node;
	bool			allocated;
};