First batch of cleanups for 4.4:
- properly get the slow clock from timer-atmel-st, tcb_clksrc and pwm-atmel-tcb - small fix in an error path for tcb_clksrc -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJWE+cSAAoJEKbNnwlvZCyzxtYP/2UiUB2aHcHiFwINhiyOr6p/ HmhJvxR0A72yq8jUkC5UEozj/U4boA66v+u/fR5DB8xV8Fj9VCoflrCqmC0VNoqT Vh8RklpO0OauiosLDC+pKlZxNHcyc/hDNCv+IeV4VIJKk6dOj+vpaHRqgYljk4/m zsUXZPKku1DZ45sQwx5a2FqEpsXlMcyawjXPZFuPHymlB2PPKiQDtvouIHOUyDoO dvlX7C7MVR5XaIiG8pSHMMmNNYhlrGnTYgUEEo0DhqKXpQLLo4XbCxdsq2hGIDhT XoXgqQVKTLVha3/tHnJjy43OqO65ptTKKMvyFyXaNhknLAz8aomJAgZXeOJSWYUB a6Z2NRKf28do7+57C95hkbWMNiTziNud903DIuK3S/6c5EmpjJ1IJupGUp4JNmkW FfT+r4s1J3sO9QNG9Y86/P2jTq3f0aIJesMpQ5mU4xkzVfFZCKeXUOylNLR37VE+ 8ofgVyC8kbqClGEuePR0KvuinIj7xGlGOmSNR+M5FR4sZVEvc6xHVwnDXcT9Hbpe pvVGbXPNfhEEP0E2gqf1GFcqAx8bYQzeFOh0CSA8sEYqP+c8GgfFIgjeP31W4Gti gjgYeAAUg8i45WZBCPYAJbpsDwzxv8vvpDvioqVJDdQo+aJv0TA6ITl9eHHj0mgV 8WpYxQWiZ2PcBNGtqteK =UbC0 -----END PGP SIGNATURE----- Merge tag 'at91-cleanup-4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux into next/drivers Merge "First batch of cleanups for 4.4:" from Alexandre Belloni: - properly get the slow clock from timer-atmel-st, tcb_clksrc and pwm-atmel-tcb - small fix in an error path for tcb_clksrc * tag 'at91-cleanup-4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: misc: atmel_tclib: get and use slow clock clocksource: tcb_clksrc: fix setup_clkevents error path clocksource: atmel-st: get and use slow clock
This commit is contained in:
Коммит
f3c65c2892
|
@ -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];
|
||||
|
||||
/* try to enable t2 clk to avoid future errors in mode change */
|
||||
ret = clk_prepare_enable(t2_clk);
|
||||
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) {
|
||||
clk_disable_unprepare(tc->slow_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk_disable(t2_clk);
|
||||
|
||||
clkevt.regs = tc->regs;
|
||||
|
@ -208,7 +215,8 @@ 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_disable_unprepare(t2_clk);
|
||||
clk_unprepare(t2_clk);
|
||||
clk_disable_unprepare(tc->slow_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
|
@ -33,9 +34,7 @@ static unsigned long last_crtr;
|
|||
static u32 irqmask;
|
||||
static struct clock_event_device clkevt;
|
||||
static struct regmap *regmap_st;
|
||||
|
||||
#define AT91_SLOW_CLOCK 32768
|
||||
#define RM9200_TIMER_LATCH ((AT91_SLOW_CLOCK + HZ/2) / HZ)
|
||||
static int timer_latch;
|
||||
|
||||
/*
|
||||
* The ST_CRTR is updated asynchronously to the master clock ... but
|
||||
|
@ -82,8 +81,8 @@ static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
|
|||
if (sr & AT91_ST_PITS) {
|
||||
u32 crtr = read_CRTR();
|
||||
|
||||
while (((crtr - last_crtr) & AT91_ST_CRTV) >= RM9200_TIMER_LATCH) {
|
||||
last_crtr += RM9200_TIMER_LATCH;
|
||||
while (((crtr - last_crtr) & AT91_ST_CRTV) >= timer_latch) {
|
||||
last_crtr += timer_latch;
|
||||
clkevt.event_handler(&clkevt);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
|
@ -144,7 +143,7 @@ static int clkevt32k_set_periodic(struct clock_event_device *dev)
|
|||
|
||||
/* PIT for periodic irqs; fixed rate of 1/HZ */
|
||||
irqmask = AT91_ST_PITS;
|
||||
regmap_write(regmap_st, AT91_ST_PIMR, RM9200_TIMER_LATCH);
|
||||
regmap_write(regmap_st, AT91_ST_PIMR, timer_latch);
|
||||
regmap_write(regmap_st, AT91_ST_IER, irqmask);
|
||||
return 0;
|
||||
}
|
||||
|
@ -197,7 +196,8 @@ static struct clock_event_device clkevt = {
|
|||
*/
|
||||
static void __init atmel_st_timer_init(struct device_node *node)
|
||||
{
|
||||
unsigned int val;
|
||||
struct clk *sclk;
|
||||
unsigned int sclk_rate, val;
|
||||
int irq, ret;
|
||||
|
||||
regmap_st = syscon_node_to_regmap(node);
|
||||
|
@ -221,6 +221,19 @@ static void __init atmel_st_timer_init(struct device_node *node)
|
|||
if (ret)
|
||||
panic(pr_fmt("Unable to setup IRQ\n"));
|
||||
|
||||
sclk = of_clk_get(node, 0);
|
||||
if (IS_ERR(sclk))
|
||||
panic(pr_fmt("Unable to get slow clock\n"));
|
||||
|
||||
clk_prepare_enable(sclk);
|
||||
if (ret)
|
||||
panic(pr_fmt("Could not enable slow clock\n"));
|
||||
|
||||
sclk_rate = clk_get_rate(sclk);
|
||||
if (!sclk_rate)
|
||||
panic(pr_fmt("Invalid slow clock rate\n"));
|
||||
timer_latch = (sclk_rate + HZ / 2) / HZ;
|
||||
|
||||
/* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used
|
||||
* directly for the clocksource and all clockevents, after adjusting
|
||||
* its prescaler from the 1 Hz default.
|
||||
|
@ -229,11 +242,11 @@ static void __init atmel_st_timer_init(struct device_node *node)
|
|||
|
||||
/* Setup timer clockevent, with minimum of two ticks (important!!) */
|
||||
clkevt.cpumask = cpumask_of(0);
|
||||
clockevents_config_and_register(&clkevt, AT91_SLOW_CLOCK,
|
||||
clockevents_config_and_register(&clkevt, sclk_rate,
|
||||
2, AT91_ST_ALMV);
|
||||
|
||||
/* register clocksource */
|
||||
clocksource_register_hz(&clk32k, AT91_SLOW_CLOCK);
|
||||
clocksource_register_hz(&clk32k, sclk_rate);
|
||||
}
|
||||
CLOCKSOURCE_OF_DECLARE(atmel_st_timer, "atmel,at91rm9200-st",
|
||||
atmel_st_timer_init);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче