Commit f628c64f authored by Olof Johansson's avatar Olof Johansson

Merge tag 'at91-ab-4.6-drivers' of...

Merge tag 'at91-ab-4.6-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux into next/drivers

From Alexandre Belloni:

"This is a rework of the PMC driver. It touches multiple subsystems so
the easiest path is through arm-soc."

drivers update for 4.6:
 - Big PMC rework that touches clk, PM, usb

* tag 'at91-ab-4.6-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux:
  clk: at91: remove useless includes
  clk: at91: pmc: remove useless capacities handling
  clk: at91: pmc: drop at91_pmc_base
  usb: gadget: atmel: access the PMC using regmap
  ARM: at91: remove useless includes and function prototypes
  ARM: at91: pm: move idle functions to pm.c
  ARM: at91: pm: find and remap the pmc
  ARM: at91: pm: simply call at91_pm_init
  clk: at91: pmc: move pmc structures to C file
  clk: at91: pmc: merge at91_pmc_init in atmel_pmc_probe
  clk: at91: remove IRQ handling and use polling
  clk: at91: make use of syscon/regmap internally
  clk: at91: make use of syscon to share PMC registers in several drivers
Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 962f08f8 0002ca16
...@@ -104,6 +104,7 @@ config HAVE_AT91_USB_CLK ...@@ -104,6 +104,7 @@ config HAVE_AT91_USB_CLK
config COMMON_CLK_AT91 config COMMON_CLK_AT91
bool bool
select COMMON_CLK select COMMON_CLK
select MFD_SYSCON
config HAVE_AT91_SMD config HAVE_AT91_SMD
bool bool
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/system_misc.h>
#include "generic.h" #include "generic.h"
#include "soc.h" #include "soc.h"
...@@ -33,7 +32,6 @@ static void __init at91rm9200_dt_device_init(void) ...@@ -33,7 +32,6 @@ static void __init at91rm9200_dt_device_init(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, soc_dev); of_platform_populate(NULL, of_default_bus_match_table, NULL, soc_dev);
arm_pm_idle = at91rm9200_idle;
at91rm9200_pm_init(); at91rm9200_pm_init();
} }
......
...@@ -62,8 +62,6 @@ static void __init at91sam9_common_init(void) ...@@ -62,8 +62,6 @@ static void __init at91sam9_common_init(void)
soc_dev = soc_device_to_device(soc); soc_dev = soc_device_to_device(soc);
of_platform_populate(NULL, of_default_bus_match_table, NULL, soc_dev); of_platform_populate(NULL, of_default_bus_match_table, NULL, soc_dev);
arm_pm_idle = at91sam9_idle;
} }
static void __init at91sam9_dt_device_init(void) static void __init at91sam9_dt_device_init(void)
......
...@@ -11,27 +11,18 @@ ...@@ -11,27 +11,18 @@
#ifndef _AT91_GENERIC_H #ifndef _AT91_GENERIC_H
#define _AT91_GENERIC_H #define _AT91_GENERIC_H
#include <linux/of.h>
#include <linux/reboot.h>
/* Map io */
extern void __init at91_map_io(void);
extern void __init at91_alt_map_io(void);
/* idle */
extern void at91rm9200_idle(void);
extern void at91sam9_idle(void);
#ifdef CONFIG_PM #ifdef CONFIG_PM
extern void __init at91rm9200_pm_init(void); extern void __init at91rm9200_pm_init(void);
extern void __init at91sam9260_pm_init(void); extern void __init at91sam9260_pm_init(void);
extern void __init at91sam9g45_pm_init(void); extern void __init at91sam9g45_pm_init(void);
extern void __init at91sam9x5_pm_init(void); extern void __init at91sam9x5_pm_init(void);
extern void __init sama5_pm_init(void);
#else #else
static inline void __init at91rm9200_pm_init(void) { } static inline void __init at91rm9200_pm_init(void) { }
static inline void __init at91sam9260_pm_init(void) { } static inline void __init at91sam9260_pm_init(void) { }
static inline void __init at91sam9g45_pm_init(void) { } static inline void __init at91sam9g45_pm_init(void) { }
static inline void __init at91sam9x5_pm_init(void) { } static inline void __init at91sam9x5_pm_init(void) { }
static inline void __init sama5_pm_init(void) { }
#endif #endif
#endif /* _AT91_GENERIC_H */ #endif /* _AT91_GENERIC_H */
...@@ -31,10 +31,13 @@ ...@@ -31,10 +31,13 @@
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/fncpy.h> #include <asm/fncpy.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/system_misc.h>
#include "generic.h" #include "generic.h"
#include "pm.h" #include "pm.h"
static void __iomem *pmc;
/* /*
* FIXME: this is needed to communicate between the pinctrl driver and * FIXME: this is needed to communicate between the pinctrl driver and
* the PM implementation in the machine. Possibly part of the PM * the PM implementation in the machine. Possibly part of the PM
...@@ -87,7 +90,7 @@ static int at91_pm_verify_clocks(void) ...@@ -87,7 +90,7 @@ static int at91_pm_verify_clocks(void)
unsigned long scsr; unsigned long scsr;
int i; int i;
scsr = at91_pmc_read(AT91_PMC_SCSR); scsr = readl(pmc + AT91_PMC_SCSR);
/* USB must not be using PLLB */ /* USB must not be using PLLB */
if ((scsr & at91_pm_data.uhp_udp_mask) != 0) { if ((scsr & at91_pm_data.uhp_udp_mask) != 0) {
...@@ -101,8 +104,7 @@ static int at91_pm_verify_clocks(void) ...@@ -101,8 +104,7 @@ static int at91_pm_verify_clocks(void)
if ((scsr & (AT91_PMC_PCK0 << i)) == 0) if ((scsr & (AT91_PMC_PCK0 << i)) == 0)
continue; continue;
css = readl(pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
css = at91_pmc_read(AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
if (css != AT91_PMC_CSS_SLOW) { if (css != AT91_PMC_CSS_SLOW) {
pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css); pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css);
return 0; return 0;
...@@ -145,8 +147,8 @@ static void at91_pm_suspend(suspend_state_t state) ...@@ -145,8 +147,8 @@ static void at91_pm_suspend(suspend_state_t state)
flush_cache_all(); flush_cache_all();
outer_disable(); outer_disable();
at91_suspend_sram_fn(at91_pmc_base, at91_ramc_base[0], at91_suspend_sram_fn(pmc, at91_ramc_base[0],
at91_ramc_base[1], pm_data); at91_ramc_base[1], pm_data);
outer_resume(); outer_resume();
} }
...@@ -353,6 +355,21 @@ static __init void at91_dt_ramc(void) ...@@ -353,6 +355,21 @@ static __init void at91_dt_ramc(void)
at91_pm_set_standby(standby); at91_pm_set_standby(standby);
} }
void at91rm9200_idle(void)
{
/*
* Disable the processor clock. The processor will be automatically
* re-enabled by an interrupt or by a reset.
*/
writel(AT91_PMC_PCK, pmc + AT91_PMC_SCDR);
}
void at91sam9_idle(void)
{
writel(AT91_PMC_PCK, pmc + AT91_PMC_SCDR);
cpu_do_idle();
}
static void __init at91_pm_sram_init(void) static void __init at91_pm_sram_init(void)
{ {
struct gen_pool *sram_pool; struct gen_pool *sram_pool;
...@@ -399,13 +416,36 @@ static void __init at91_pm_sram_init(void) ...@@ -399,13 +416,36 @@ static void __init at91_pm_sram_init(void)
&at91_pm_suspend_in_sram, at91_pm_suspend_in_sram_sz); &at91_pm_suspend_in_sram, at91_pm_suspend_in_sram_sz);
} }
static void __init at91_pm_init(void) static const struct of_device_id atmel_pmc_ids[] __initconst = {
{ .compatible = "atmel,at91rm9200-pmc" },
{ .compatible = "atmel,at91sam9260-pmc" },
{ .compatible = "atmel,at91sam9g45-pmc" },
{ .compatible = "atmel,at91sam9n12-pmc" },
{ .compatible = "atmel,at91sam9x5-pmc" },
{ .compatible = "atmel,sama5d3-pmc" },
{ .compatible = "atmel,sama5d2-pmc" },
{ /* sentinel */ },
};
static void __init at91_pm_init(void (*pm_idle)(void))
{ {
at91_pm_sram_init(); struct device_node *pmc_np;
if (at91_cpuidle_device.dev.platform_data) if (at91_cpuidle_device.dev.platform_data)
platform_device_register(&at91_cpuidle_device); platform_device_register(&at91_cpuidle_device);
pmc_np = of_find_matching_node(NULL, atmel_pmc_ids);
pmc = of_iomap(pmc_np, 0);
if (!pmc) {
pr_err("AT91: PM not supported, PMC not found\n");
return;
}
if (pm_idle)
arm_pm_idle = pm_idle;
at91_pm_sram_init();
if (at91_suspend_sram_fn) if (at91_suspend_sram_fn)
suspend_set_ops(&at91_pm_ops); suspend_set_ops(&at91_pm_ops);
else else
...@@ -424,7 +464,7 @@ void __init at91rm9200_pm_init(void) ...@@ -424,7 +464,7 @@ void __init at91rm9200_pm_init(void)
at91_pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP; at91_pm_data.uhp_udp_mask = AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP;
at91_pm_data.memctrl = AT91_MEMCTRL_MC; at91_pm_data.memctrl = AT91_MEMCTRL_MC;
at91_pm_init(); at91_pm_init(at91rm9200_idle);
} }
void __init at91sam9260_pm_init(void) void __init at91sam9260_pm_init(void)
...@@ -432,7 +472,7 @@ void __init at91sam9260_pm_init(void) ...@@ -432,7 +472,7 @@ void __init at91sam9260_pm_init(void)
at91_dt_ramc(); at91_dt_ramc();
at91_pm_data.memctrl = AT91_MEMCTRL_SDRAMC; at91_pm_data.memctrl = AT91_MEMCTRL_SDRAMC;
at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP; at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
return at91_pm_init(); at91_pm_init(at91sam9_idle);
} }
void __init at91sam9g45_pm_init(void) void __init at91sam9g45_pm_init(void)
...@@ -440,7 +480,7 @@ void __init at91sam9g45_pm_init(void) ...@@ -440,7 +480,7 @@ void __init at91sam9g45_pm_init(void)
at91_dt_ramc(); at91_dt_ramc();
at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP; at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP;
at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR; at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
return at91_pm_init(); at91_pm_init(at91sam9_idle);
} }
void __init at91sam9x5_pm_init(void) void __init at91sam9x5_pm_init(void)
...@@ -448,5 +488,13 @@ void __init at91sam9x5_pm_init(void) ...@@ -448,5 +488,13 @@ void __init at91sam9x5_pm_init(void)
at91_dt_ramc(); at91_dt_ramc();
at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP; at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR; at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
return at91_pm_init(); at91_pm_init(at91sam9_idle);
}
void __init sama5_pm_init(void)
{
at91_dt_ramc();
at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP;
at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
at91_pm_init(NULL);
} }
...@@ -51,7 +51,7 @@ static void __init sama5_dt_device_init(void) ...@@ -51,7 +51,7 @@ static void __init sama5_dt_device_init(void)
soc_dev = soc_device_to_device(soc); soc_dev = soc_device_to_device(soc);
of_platform_populate(NULL, of_default_bus_match_table, NULL, soc_dev); of_platform_populate(NULL, of_default_bus_match_table, NULL, soc_dev);
at91sam9x5_pm_init(); sama5_pm_init();
} }
static const char *const sama5_dt_board_compat[] __initconst = { static const char *const sama5_dt_board_compat[] __initconst = {
......
...@@ -15,8 +15,8 @@ ...@@ -15,8 +15,8 @@
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h> #include <linux/clk/at91_pmc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/mfd/syscon.h>
#include <linux/io.h> #include <linux/regmap.h>
#include "pmc.h" #include "pmc.h"
...@@ -28,8 +28,9 @@ ...@@ -28,8 +28,9 @@
struct clk_generated { struct clk_generated {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct regmap *regmap;
struct clk_range range; struct clk_range range;
spinlock_t *lock;
u32 id; u32 id;
u32 gckdiv; u32 gckdiv;
u8 parent_id; u8 parent_id;
...@@ -41,49 +42,52 @@ struct clk_generated { ...@@ -41,49 +42,52 @@ struct clk_generated {
static int clk_generated_enable(struct clk_hw *hw) static int clk_generated_enable(struct clk_hw *hw)
{ {
struct clk_generated *gck = to_clk_generated(hw); struct clk_generated *gck = to_clk_generated(hw);
struct at91_pmc *pmc = gck->pmc; unsigned long flags;
u32 tmp;
pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n", pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n",
__func__, gck->gckdiv, gck->parent_id); __func__, gck->gckdiv, gck->parent_id);
pmc_lock(pmc); spin_lock_irqsave(gck->lock, flags);
pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); regmap_write(gck->regmap, AT91_PMC_PCR,
tmp = pmc_read(pmc, AT91_PMC_PCR) & (gck->id & AT91_PMC_PCR_PID_MASK));
~(AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK); regmap_update_bits(gck->regmap, AT91_PMC_PCR,
pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_GCKCSS(gck->parent_id) AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK |
| AT91_PMC_PCR_CMD AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
| AT91_PMC_PCR_GCKDIV(gck->gckdiv) AT91_PMC_PCR_GCKCSS(gck->parent_id) |
| AT91_PMC_PCR_GCKEN); AT91_PMC_PCR_CMD |
pmc_unlock(pmc); AT91_PMC_PCR_GCKDIV(gck->gckdiv) |
AT91_PMC_PCR_GCKEN);
spin_unlock_irqrestore(gck->lock, flags);
return 0; return 0;
} }
static void clk_generated_disable(struct clk_hw *hw) static void clk_generated_disable(struct clk_hw *hw)
{ {
struct clk_generated *gck = to_clk_generated(hw); struct clk_generated *gck = to_clk_generated(hw);
struct at91_pmc *pmc = gck->pmc; unsigned long flags;
u32 tmp;
spin_lock_irqsave(gck->lock, flags);
pmc_lock(pmc); regmap_write(gck->regmap, AT91_PMC_PCR,
pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); (gck->id & AT91_PMC_PCR_PID_MASK));
tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_GCKEN; regmap_update_bits(gck->regmap, AT91_PMC_PCR,
pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_CMD); AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
pmc_unlock(pmc); AT91_PMC_PCR_CMD);
spin_unlock_irqrestore(gck->lock, flags);
} }
static int clk_generated_is_enabled(struct clk_hw *hw) static int clk_generated_is_enabled(struct clk_hw *hw)
{ {
struct clk_generated *gck = to_clk_generated(hw); struct clk_generated *gck = to_clk_generated(hw);
struct at91_pmc *pmc = gck->pmc; unsigned long flags;
int ret; unsigned int status;
pmc_lock(pmc); spin_lock_irqsave(gck->lock, flags);
pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); regmap_write(gck->regmap, AT91_PMC_PCR,
ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_GCKEN); (gck->id & AT91_PMC_PCR_PID_MASK));
pmc_unlock(pmc); regmap_read(gck->regmap, AT91_PMC_PCR, &status);
spin_unlock_irqrestore(gck->lock, flags);
return ret; return status & AT91_PMC_PCR_GCKEN ? 1 : 0;
} }
static unsigned long static unsigned long
...@@ -214,13 +218,14 @@ static const struct clk_ops generated_ops = { ...@@ -214,13 +218,14 @@ static const struct clk_ops generated_ops = {
*/ */
static void clk_generated_startup(struct clk_generated *gck) static void clk_generated_startup(struct clk_generated *gck)
{ {
struct at91_pmc *pmc = gck->pmc;
u32 tmp; u32 tmp;
unsigned long flags;
pmc_lock(pmc); spin_lock_irqsave(gck->lock, flags);
pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); regmap_write(gck->regmap, AT91_PMC_PCR,
tmp = pmc_read(pmc, AT91_PMC_PCR); (gck->id & AT91_PMC_PCR_PID_MASK));
pmc_unlock(pmc); regmap_read(gck->regmap, AT91_PMC_PCR, &tmp);
spin_unlock_irqrestore(gck->lock, flags);
gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK) gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK)
>> AT91_PMC_PCR_GCKCSS_OFFSET; >> AT91_PMC_PCR_GCKCSS_OFFSET;
...@@ -229,8 +234,8 @@ static void clk_generated_startup(struct clk_generated *gck) ...@@ -229,8 +234,8 @@ static void clk_generated_startup(struct clk_generated *gck)
} }
static struct clk * __init static struct clk * __init
at91_clk_register_generated(struct at91_pmc *pmc, const char *name, at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, const char
const char **parent_names, u8 num_parents, *name, const char **parent_names, u8 num_parents,
u8 id, const struct clk_range *range) u8 id, const struct clk_range *range)
{ {
struct clk_generated *gck; struct clk_generated *gck;
...@@ -249,7 +254,8 @@ at91_clk_register_generated(struct at91_pmc *pmc, const char *name, ...@@ -249,7 +254,8 @@ at91_clk_register_generated(struct at91_pmc *pmc, const char *name,
gck->id = id; gck->id = id;
gck->hw.init = &init; gck->hw.init = &init;
gck->pmc = pmc; gck->regmap = regmap;
gck->lock = lock;
gck->range = *range; gck->range = *range;
clk = clk_register(NULL, &gck->hw); clk = clk_register(NULL, &gck->hw);
...@@ -261,8 +267,7 @@ at91_clk_register_generated(struct at91_pmc *pmc, const char *name, ...@@ -261,8 +267,7 @@ at91_clk_register_generated(struct at91_pmc *pmc, const char *name,
return clk; return clk;
} }
void __init of_sama5d2_clk_generated_setup(struct device_node *np, void __init of_sama5d2_clk_generated_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
int num; int num;
u32 id; u32 id;
...@@ -272,6 +277,7 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np, ...@@ -272,6 +277,7 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np,
const char *parent_names[GENERATED_SOURCE_MAX]; const char *parent_names[GENERATED_SOURCE_MAX];
struct device_node *gcknp; struct device_node *gcknp;
struct clk_range range = CLK_RANGE(0, 0); struct clk_range range = CLK_RANGE(0, 0);
struct regmap *regmap;
num_parents = of_clk_get_parent_count(np); num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > GENERATED_SOURCE_MAX) if (num_parents <= 0 || num_parents > GENERATED_SOURCE_MAX)
...@@ -283,6 +289,10 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np, ...@@ -283,6 +289,10 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np,
if (!num || num > PERIPHERAL_MAX) if (!num || num > PERIPHERAL_MAX)
return; return;
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
for_each_child_of_node(np, gcknp) { for_each_child_of_node(np, gcknp) {
if (of_property_read_u32(gcknp, "reg", &id)) if (of_property_read_u32(gcknp, "reg", &id))
continue; continue;
...@@ -296,11 +306,14 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np, ...@@ -296,11 +306,14 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np,
of_at91_get_clk_range(gcknp, "atmel,clk-output-range", of_at91_get_clk_range(gcknp, "atmel,clk-output-range",
&range); &range);
clk = at91_clk_register_generated(pmc, name, parent_names, clk = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
num_parents, id, &range); parent_names, num_parents,
id, &range);
if (IS_ERR(clk)) if (IS_ERR(clk))
continue; continue;
of_clk_add_provider(gcknp, of_clk_src_simple_get, clk); of_clk_add_provider(gcknp, of_clk_src_simple_get, clk);
} }
} }
CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated",
of_sama5d2_clk_generated_setup);
...@@ -15,15 +15,9 @@ ...@@ -15,15 +15,9 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h> #include <linux/clk/at91_pmc.h>
#include <linux/delay.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/regmap.h>
#include <linux/of_irq.h> #include <linux/mfd/syscon.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include "pmc.h" #include "pmc.h"
...@@ -31,7 +25,7 @@ ...@@ -31,7 +25,7 @@
struct clk_sama5d4_h32mx { struct clk_sama5d4_h32mx {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct regmap *regmap;
}; };
#define to_clk_sama5d4_h32mx(hw) container_of(hw, struct clk_sama5d4_h32mx, hw) #define to_clk_sama5d4_h32mx(hw) container_of(hw, struct clk_sama5d4_h32mx, hw)
...@@ -40,8 +34,10 @@ static unsigned long clk_sama5d4_h32mx_recalc_rate(struct clk_hw *hw, ...@@ -40,8 +34,10 @@ static unsigned long clk_sama5d4_h32mx_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw); struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw);
unsigned int mckr;
if (pmc_read(h32mxclk->pmc, AT91_PMC_MCKR) & AT91_PMC_H32MXDIV) regmap_read(h32mxclk->regmap, AT91_PMC_MCKR, &mckr);
if (mckr & AT91_PMC_H32MXDIV)
return parent_rate / 2; return parent_rate / 2;
if (parent_rate > H32MX_MAX_FREQ) if (parent_rate > H32MX_MAX_FREQ)
...@@ -70,18 +66,16 @@ static int clk_sama5d4_h32mx_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -70,18 +66,16 @@ static int clk_sama5d4_h32mx_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw); struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw);
struct at91_pmc *pmc = h32mxclk->pmc; u32 mckr = 0;
u32 tmp;
if (parent_rate != rate && (parent_rate / 2) != rate) if (parent_rate != rate && (parent_rate / 2) != rate)
return -EINVAL; return -EINVAL;
pmc_lock(pmc);
tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_H32MXDIV;
if ((parent_rate / 2) == rate) if ((parent_rate / 2) == rate)
tmp |= AT91_PMC_H32MXDIV; mckr = AT91_PMC_H32MXDIV;
pmc_write(pmc, AT91_PMC_MCKR, tmp);
pmc_unlock(pmc); regmap_update_bits(h32mxclk->regmap, AT91_PMC_MCKR,
AT91_PMC_H32MXDIV, mckr);
return 0; return 0;
} }
...@@ -92,14 +86,18 @@ static const struct clk_ops h32mx_ops = { ...@@ -92,14 +86,18 @@ static const struct clk_ops h32mx_ops = {
.set_rate = clk_sama5d4_h32mx_set_rate, .set_rate = clk_sama5d4_h32mx_set_rate,
}; };
void __init of_sama5d4_clk_h32mx_setup(struct device_node *np, static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
struct clk_sama5d4_h32mx *h32mxclk; struct clk_sama5d4_h32mx *h32mxclk;
struct clk_init_data init; struct clk_init_data init;
const char *parent_name; const char *parent_name;
struct regmap *regmap;
struct clk *clk; struct clk *clk;
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
h32mxclk = kzalloc(sizeof(*h32mxclk), GFP_KERNEL); h32mxclk = kzalloc(sizeof(*h32mxclk), GFP_KERNEL);
if (!h32mxclk) if (!h32mxclk)
return; return;
...@@ -113,7 +111,7 @@ void __init of_sama5d4_clk_h32mx_setup(struct device_node *np, ...@@ -113,7 +111,7 @@ void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
init.flags = CLK_SET_RATE_GATE; init.flags = CLK_SET_RATE_GATE;
h32mxclk->hw.init = &init; h32mxclk->hw.init = &init;
h32mxclk->pmc = pmc; h32mxclk->regmap = regmap;
clk = clk_register(NULL, &h32mxclk->hw); clk = clk_register(NULL, &h32mxclk->hw);
if (!clk) { if (!clk) {
...@@ -123,3 +121,5 @@ void __init of_sama5d4_clk_h32mx_setup(struct device_node *np, ...@@ -123,3 +121,5 @@ void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
of_clk_add_provider(np, of_clk_src_simple_get, clk); of_clk_add_provider(np, of_clk_src_simple_get, clk);
} }
CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx",
of_sama5d4_clk_h32mx_setup);
This diff is collapsed.
...@@ -12,13 +12,8 @@ ...@@ -12,13 +12,8 @@
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h> #include <linux/clk/at91_pmc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/mfd/syscon.h>
#include <linux/of_irq.h> #include <linux/regmap.h>
#include <linux/io.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include "pmc.h" #include "pmc.h"
...@@ -44,32 +39,26 @@ struct clk_master_layout { ...@@ -44,32 +39,26 @@ struct clk_master_layout {
struct clk_master { struct clk_master {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct regmap *regmap;
unsigned int irq;
wait_queue_head_t wait;
const struct clk_master_layout *layout; const struct clk_master_layout *layout;
const struct clk_master_characteristics *characteristics; const struct clk_master_characteristics *characteristics;
}; };
static irqreturn_t clk_master_irq_handler(int irq, void *dev_id) static inline bool clk_master_ready(struct regmap *regmap)
{ {
struct clk_master *master = (struct clk_master *)dev_id; unsigned int status;
wake_up(&master->wait); regmap_read(regmap, AT91_PMC_SR, &status);
disable_irq_nosync(master->irq);
return IRQ_HANDLED; return status & AT91_PMC_MCKRDY ? 1 : 0;
} }
static int clk_master_prepare(struct clk_hw *hw) static int clk_master_prepare(struct clk_hw *hw)
{ {
struct clk_master *master = to_clk_master(hw); struct clk_master *master = to_clk_master(hw);
struct at91_pmc *pmc = master->pmc;
while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY)) { while (!clk_master_ready(master->regmap))
enable_irq(master->irq); cpu_relax();
wait_event(master->wait,
pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY);
}
return 0; return 0;
} }
...@@ -78,7 +67,7 @@ static int clk_master_is_prepared(struct clk_hw *hw) ...@@ -78,7 +67,7 @@ static int clk_master_is_prepared(struct clk_hw *hw)
{ {
struct clk_master *master = to_clk_master(hw); struct clk_master *master = to_clk_master(hw);
return !!(pmc_read(master->pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY); return clk_master_ready(master->regmap);
} }
static unsigned long clk_master_recalc_rate(struct clk_hw *hw, static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
...@@ -88,18 +77,16 @@ static unsigned long clk_master_recalc_rate(struct clk_hw *hw, ...@@ -88,18 +77,16 @@ static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
u8 div; u8 div;
unsigned long rate = parent_rate; unsigned long rate = parent_rate;
struct clk_master *master = to_clk_master(hw); struct clk_master *master = to_clk_master(hw);
struct at91_pmc *pmc = master->pmc;
const struct clk_master_layout *layout = master->layout; const struct clk_master_layout *layout = master->layout;
const struct clk_master_characteristics *characteristics = const struct clk_master_characteristics *characteristics =
master->characteristics; master->characteristics;
u32 tmp; unsigned int mckr;
pmc_lock(pmc); regmap_read(master->regmap, AT91_PMC_MCKR, &mckr);
tmp = pmc_read(pmc, AT91_PMC_MCKR) & layout->mask; mckr &= layout->mask;
pmc_unlock(pmc);
pres = (tmp >> layout->pres_shift) & MASTER_PRES_MASK; pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK;
div = (tmp >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK; div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX) if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX)
rate /= 3; rate /= 3;
...@@ -119,9 +106,11 @@ static unsigned long clk_master_recalc_rate(struct clk_hw *hw, ...@@ -119,9 +106,11 @@ static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
static u8 clk_master_get_parent(struct clk_hw *hw) static u8 clk_master_get_parent(struct clk_hw *hw)
{ {
struct clk_master *master = to_clk_master(hw); struct clk_master *master = to_clk_master(hw);
struct at91_pmc *pmc = master->pmc; unsigned int mckr;
return pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_CSS; regmap_read(master->regmap, AT91_PMC_MCKR, &mckr);
return mckr & AT91_PMC_CSS;
} }
static const struct clk_ops master_ops = { static const struct clk_ops master_ops = {
...@@ -132,18 +121,17 @@ static const struct clk_ops master_ops = { ...@@ -132,18 +121,17 @@ static const struct clk_ops master_ops = {
}; };
static struct clk * __init static struct clk * __init
at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq, at91_clk_register_master(struct regmap *regmap,
const char *name, int num_parents, const char *name, int num_parents,
const char **parent_names, const char **parent_names,
const struct clk_master_layout *layout, const struct clk_master_layout *layout,
const struct clk_master_characteristics *characteristics) const struct clk_master_characteristics *characteristics)
{ {
int ret;
struct clk_master *master; struct clk_master *master;
struct clk *clk = NULL; struct clk *clk = NULL;
struct clk_init_data init; struct clk_init_data init;
if (!pmc || !irq || !name || !num_parents || !parent_names) if (!name || !num_parents || !parent_names)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
master = kzalloc(sizeof(*master), GFP_KERNEL); master = kzalloc(sizeof(*master), GFP_KERNEL);
...@@ -159,20 +147,10 @@ at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq, ...@@ -159,20 +147,10 @@ at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq,
master->hw.init = &init; master->hw.init = &init;
master->layout = layout; master->layout = layout;
master->characteristics = characteristics; master->characteristics = characteristics;
master->pmc = pmc; master->regmap = regmap;
master->irq = irq;
init_waitqueue_head(&master->wait);
irq_set_status_flags(master->irq, IRQ_NOAUTOEN);
ret = request_irq(master->irq, clk_master_irq_handler,
IRQF_TRIGGER_HIGH, "clk-master", master);
if (ret) {
kfree(master);
return ERR_PTR(ret);
}
clk = clk_register(NULL, &master->hw); clk = clk_register(NULL, &master->hw);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
free_irq(master->irq, master);
kfree(master); kfree(master);
} }
...@@ -217,15 +195,15 @@ of_at91_clk_master_get_characteristics(struct device_node *np) ...@@ -217,15 +195,15 @@ of_at91_clk_master_get_characteristics(struct device_node *np)
} }
static void __init static void __init
of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc, of_at91_clk_master_setup(struct device_node *np,
const struct clk_master_layout *layout) const struct clk_master_layout *layout)
{ {
struct clk *clk; struct clk *clk;
int num_parents; int num_parents;
unsigned int irq;
const char *parent_names[MASTER_SOURCE_MAX]; const char *parent_names[MASTER_SOURCE_MAX];
const char *name = np->name; const char *name = np->name;
struct clk_master_characteristics *characteristics; struct clk_master_characteristics *characteristics;
struct regmap *regmap;
num_parents = of_clk_get_parent_count(np); num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX) if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX)
...@@ -239,11 +217,11 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc, ...@@ -239,11 +217,11 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
if (!characteristics) if (!characteristics)
return; return;
irq = irq_of_parse_and_map(np, 0); regmap = syscon_node_to_regmap(of_get_parent(np));
if (!irq) if (IS_ERR(regmap))
goto out_free_characteristics; return;
clk = at91_clk_register_master(pmc, irq, name, num_parents, clk = at91_clk_register_master(regmap, name, num_parents,
parent_names, layout, parent_names, layout,
characteristics); characteristics);
if (IS_ERR(clk)) if (IS_ERR(clk))
...@@ -256,14 +234,16 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc, ...@@ -256,14 +234,16 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
kfree(characteristics); kfree(characteristics);
} }
void __init of_at91rm9200_clk_master_setup(struct device_node *np, static void __init of_at91rm9200_clk_master_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
of_at91_clk_master_setup(np, pmc, &at91rm9200_master_layout); of_at91_clk_master_setup(np, &at91rm9200_master_layout);
} }
CLK_OF_DECLARE(at91rm9200_clk_master, "atmel,at91rm9200-clk-master",
of_at91rm9200_clk_master_setup);
void __init of_at91sam9x5_clk_master_setup(struct device_node *np, static void __init of_at91sam9x5_clk_master_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
of_at91_clk_master_setup(np, pmc, &at91sam9x5_master_layout); of_at91_clk_master_setup(np, &at91sam9x5_master_layout);
} }
CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master",
of_at91sam9x5_clk_master_setup);
...@@ -12,11 +12,13 @@ ...@@ -12,11 +12,13 @@
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h> #include <linux/clk/at91_pmc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/mfd/syscon.h>
#include <linux/io.h> #include <linux/regmap.h>
#include "pmc.h" #include "pmc.h"
DEFINE_SPINLOCK(pmc_pcr_lock);
#define PERIPHERAL_MAX 64 #define PERIPHERAL_MAX 64
#define PERIPHERAL_AT91RM9200 0 #define PERIPHERAL_AT91RM9200 0
...@@ -33,7 +35,7 @@ ...@@ -33,7 +35,7 @@
struct clk_peripheral { struct clk_peripheral {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct regmap *regmap;
u32 id; u32 id;
}; };
...@@ -41,8 +43,9 @@ struct clk_peripheral { ...@@ -41,8 +43,9 @@ struct clk_peripheral {
struct clk_sam9x5_peripheral { struct clk_sam9x5_peripheral {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct regmap *regmap;
struct clk_range range; struct clk_range range;
spinlock_t *lock;
u32 id; u32 id;
u32 div; u32 div;
bool auto_div; bool auto_div;
...@@ -54,7 +57,6 @@ struct clk_sam9x5_peripheral { ...@@ -54,7 +57,6 @@ struct clk_sam9x5_peripheral {
static int clk_peripheral_enable(struct clk_hw *hw) static int clk_peripheral_enable(struct clk_hw *hw)
{ {
struct clk_peripheral *periph = to_clk_peripheral(hw); struct clk_peripheral *periph = to_clk_peripheral(hw);
struct at91_pmc *pmc = periph->pmc;
int offset = AT91_PMC_PCER; int offset = AT91_PMC_PCER;
u32 id = periph->id; u32 id = periph->id;
...@@ -62,14 +64,14 @@ static int clk_peripheral_enable(struct clk_hw *hw) ...@@ -62,14 +64,14 @@ static int clk_peripheral_enable(struct clk_hw *hw)
return 0; return 0;
if (id > PERIPHERAL_ID_MAX) if (id > PERIPHERAL_ID_MAX)
offset = AT91_PMC_PCER1; offset = AT91_PMC_PCER1;
pmc_write(pmc, offset, PERIPHERAL_MASK(id)); regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id));
return 0; return 0;
} }
static void clk_peripheral_disable(struct clk_hw *hw) static void clk_peripheral_disable(struct clk_hw *hw)
{ {
struct clk_peripheral *periph = to_clk_peripheral(hw); struct clk_peripheral *periph = to_clk_peripheral(hw);
struct at91_pmc *pmc = periph->pmc;
int offset = AT91_PMC_PCDR; int offset = AT91_PMC_PCDR;
u32 id = periph->id; u32 id = periph->id;
...@@ -77,21 +79,23 @@ static void clk_peripheral_disable(struct clk_hw *hw) ...@@ -77,21 +79,23 @@ static void clk_peripheral_disable(struct clk_hw *hw)
return; return;
if (id > PERIPHERAL_ID_MAX) if (id > PERIPHERAL_ID_MAX)
offset = AT91_PMC_PCDR1; offset = AT91_PMC_PCDR1;
pmc_write(pmc, offset, PERIPHERAL_MASK(id)); regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id));
} }
static int clk_peripheral_is_enabled(struct clk_hw *hw) static int clk_peripheral_is_enabled(struct clk_hw *hw)
{ {
struct clk_peripheral *periph = to_clk_peripheral(hw); struct clk_peripheral *periph = to_clk_peripheral(hw);
struct at91_pmc *pmc = periph->pmc;
int offset = AT91_PMC_PCSR; int offset = AT91_PMC_PCSR;
unsigned int status;
u32 id = periph->id; u32 id = periph->id;
if (id < PERIPHERAL_ID_MIN) if (id < PERIPHERAL_ID_MIN)
return 1; return 1;
if (id > PERIPHERAL_ID_MAX) if (id > PERIPHERAL_ID_MAX)
offset = AT91_PMC_PCSR1; offset = AT91_PMC_PCSR1;
return !!(pmc_read(pmc, offset) & PERIPHERAL_MASK(id)); regmap_read(periph->regmap, offset, &status);
return status & PERIPHERAL_MASK(id) ? 1 : 0;
} }
static const struct clk_ops peripheral_ops = { static const struct clk_ops peripheral_ops = {
...@@ -101,14 +105,14 @@ static const struct clk_ops peripheral_ops = { ...@@ -101,14 +105,14 @@ static const struct clk_ops peripheral_ops = {
}; };
static struct clk * __init static struct clk * __init
at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name, at91_clk_register_peripheral(struct regmap *regmap, const char *name,
const char *parent_name, u32 id) const char *parent_name, u32 id)
{ {
struct clk_peripheral *periph; struct clk_peripheral *periph;
struct clk *clk = NULL; struct clk *clk = NULL;
struct clk_init_data init; struct clk_init_data init;
if (!pmc || !name || !parent_name || id > PERIPHERAL_ID_MAX) if (!name || !parent_name || id > PERIPHERAL_ID_MAX)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
periph = kzalloc(sizeof(*periph), GFP_KERNEL); periph = kzalloc(sizeof(*periph), GFP_KERNEL);
...@@ -123,7 +127,7 @@ at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name, ...@@ -123,7 +127,7 @@ at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name,
periph->id = id; periph->id = id;
periph->hw.init = &init; periph->hw.init = &init;
periph->pmc = pmc; periph->regmap = regmap;
clk = clk_register(NULL, &periph->hw); clk = clk_register(NULL, &periph->hw);
if (IS_ERR(clk)) if (IS_ERR(clk))
...@@ -160,53 +164,58 @@ static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph) ...@@ -160,53 +164,58 @@ static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
static int clk_sam9x5_peripheral_enable(struct clk_hw *hw) static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
{ {
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
struct at91_pmc *pmc = periph->pmc; unsigned long flags;
u32 tmp;
if (periph->id < PERIPHERAL_ID_MIN) if (periph->id < PERIPHERAL_ID_MIN)
return 0; return 0;
pmc_lock(pmc); spin_lock_irqsave(periph->lock, flags);
pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK)); regmap_write(periph->regmap, AT91_PMC_PCR,
tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_DIV_MASK; (periph->id & AT91_PMC_PCR_PID_MASK));
pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_DIV(periph->div) regmap_update_bits(periph->regmap, AT91_PMC_PCR,
| AT91_PMC_PCR_CMD AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD |
| AT91_PMC_PCR_EN); AT91_PMC_PCR_EN,
pmc_unlock(pmc); AT91_PMC_PCR_DIV(periph->div) |
AT91_PMC_PCR_CMD |
AT91_PMC_PCR_EN);
spin_unlock_irqrestore(periph->lock, flags);
return 0; return 0;
} }
static void clk_sam9x5_peripheral_disable(struct clk_hw *hw) static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
{ {
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
struct at91_pmc *pmc = periph->pmc; unsigned long flags;
u32 tmp;
if (periph->id < PERIPHERAL_ID_MIN) if (periph->id < PERIPHERAL_ID_MIN)
return; return;
pmc_lock(pmc); spin_lock_irqsave(periph->lock, flags);
pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK)); regmap_write(periph->regmap, AT91_PMC_PCR,
tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_EN; (periph->id & AT91_PMC_PCR_PID_MASK));
pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_CMD); regmap_update_bits(periph->regmap, AT91_PMC_PCR,
pmc_unlock(pmc); AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD,
AT91_PMC_PCR_CMD);
spin_unlock_irqrestore(periph->lock, flags);
} }
static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw) static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw)
{ {
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
struct at91_pmc *pmc = periph->pmc; unsigned long flags;
int ret; unsigned int status;
if (periph->id < PERIPHERAL_ID_MIN) if (periph->id < PERIPHERAL_ID_MIN)
return 1; return 1;
pmc_lock(pmc); spin_lock_irqsave(periph->lock, flags);
pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK)); regmap_write(periph->regmap, AT91_PMC_PCR,
ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_EN); (periph->id & AT91_PMC_PCR_PID_MASK));
pmc_unlock(pmc); regmap_read(periph->regmap, AT91_PMC_PCR, &status);
spin_unlock_irqrestore(periph->lock, flags);
return ret; return status & AT91_PMC_PCR_EN ? 1 : 0;
} }
static unsigned long static unsigned long
...@@ -214,19 +223,20 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw, ...@@ -214,19 +223,20 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
struct at91_pmc *pmc = periph->pmc; unsigned long flags;
u32 tmp; unsigned int status;
if (periph->id < PERIPHERAL_ID_MIN) if (periph->id < PERIPHERAL_ID_MIN)
return parent_rate; return parent_rate;
pmc_lock(pmc); spin_lock_irqsave(periph->lock, flags);
pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK)); regmap_write(periph->regmap, AT91_PMC_PCR,
tmp = pmc_read(pmc, AT91_PMC_PCR); (periph->id & AT91_PMC_PCR_PID_MASK));
pmc_unlock(pmc); regmap_read(periph->regmap, AT91_PMC_PCR, &status);
spin_unlock_irqrestore(periph->lock, flags);
if (tmp & AT91_PMC_PCR_EN) { if (status & AT91_PMC_PCR_EN) {
periph->div = PERIPHERAL_RSHIFT(tmp); periph->div = PERIPHERAL_RSHIFT(status);
periph->auto_div = false; periph->auto_div = false;
} else { } else {
clk_sam9x5_peripheral_autodiv(periph); clk_sam9x5_peripheral_autodiv(periph);
...@@ -318,15 +328,15 @@ static const struct clk_ops sam9x5_peripheral_ops = { ...@@ -318,15 +328,15 @@ static const struct clk_ops sam9x5_peripheral_ops = {
}; };
static struct clk * __init static struct clk * __init
at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name, at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
const char *parent_name, u32 id, const char *name, const char *parent_name,
const struct clk_range *range) u32 id, const struct clk_range *range)
{ {
struct clk_sam9x5_peripheral *periph; struct clk_sam9x5_peripheral *periph;
struct clk *clk = NULL; struct clk *clk = NULL;
struct clk_init_data init; struct clk_init_data init;
if (!pmc || !name || !parent_name) if (!name || !parent_name)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
periph = kzalloc(sizeof(*periph), GFP_KERNEL); periph = kzalloc(sizeof(*periph), GFP_KERNEL);
...@@ -342,7 +352,8 @@ at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name, ...@@ -342,7 +352,8 @@ at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name,
periph->id = id; periph->id = id;
periph->hw.init = &init; periph->hw.init = &init;
periph->div = 0; periph->div = 0;
periph->pmc = pmc; periph->regmap = regmap;
periph->lock = lock;
periph->auto_div = true; periph->auto_div = true;
periph->range = *range; periph->range = *range;
...@@ -356,7 +367,7 @@ at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name, ...@@ -356,7 +367,7 @@ at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name,
} }
static void __init static void __init
of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type) of_at91_clk_periph_setup(struct device_node *np, u8 type)
{ {
int num; int num;
u32 id; u32 id;
...@@ -364,6 +375,7 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type) ...@@ -364,6 +375,7 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
const char *parent_name; const char *parent_name;
const char *name; const char *name;
struct device_node *periphclknp; struct device_node *periphclknp;
struct regmap *regmap;
parent_name = of_clk_get_parent_name(np, 0); parent_name = of_clk_get_parent_name(np, 0);
if (!parent_name) if (!parent_name)
...@@ -373,6 +385,10 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type) ...@@ -373,6 +385,10 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
if (!num || num > PERIPHERAL_MAX) if (!num || num > PERIPHERAL_MAX)
return; return;
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
for_each_child_of_node(np, periphclknp) { for_each_child_of_node(np, periphclknp) {
if (of_property_read_u32(periphclknp, "reg", &id)) if (of_property_read_u32(periphclknp, "reg", &id))
continue; continue;
...@@ -384,7 +400,7 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type) ...@@ -384,7 +400,7 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
name = periphclknp->name; name = periphclknp->name;
if (type == PERIPHERAL_AT91RM9200) { if (type == PERIPHERAL_AT91RM9200) {
clk = at91_clk_register_peripheral(pmc, name, clk = at91_clk_register_peripheral(regmap, name,
parent_name, id); parent_name, id);
} else { } else {
struct clk_range range = CLK_RANGE(0, 0); struct clk_range range = CLK_RANGE(0, 0);
...@@ -393,7 +409,9 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type) ...@@ -393,7 +409,9 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
"atmel,clk-output-range", "atmel,clk-output-range",
&range); &range);
clk = at91_clk_register_sam9x5_peripheral(pmc, name, clk = at91_clk_register_sam9x5_peripheral(regmap,
&pmc_pcr_lock,
name,
parent_name, parent_name,
id, &range); id, &range);
} }
...@@ -405,14 +423,17 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type) ...@@ -405,14 +423,17 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
} }
} }
void __init of_at91rm9200_clk_periph_setup(struct device_node *np, static void __init of_at91rm9200_clk_periph_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91RM9200); of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200);
} }
CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral",
of_at91rm9200_clk_periph_setup);
void __init of_at91sam9x5_clk_periph_setup(struct device_node *np, static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91SAM9X5); of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5);
} }
CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral",
of_at91sam9x5_clk_periph_setup);
...@@ -12,14 +12,8 @@ ...@@ -12,14 +12,8 @@
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h> #include <linux/clk/at91_pmc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/mfd/syscon.h>
#include <linux/of_irq.h> #include <linux/regmap.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include "pmc.h" #include "pmc.h"
...@@ -58,9 +52,7 @@ struct clk_pll_layout { ...@@ -58,9 +52,7 @@ struct clk_pll_layout {
struct clk_pll { struct clk_pll {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct regmap *regmap;
unsigned int irq;
wait_queue_head_t wait;
u8 id; u8 id;
u8 div; u8 div;
u8 range; u8 range;
...@@ -69,20 +61,19 @@ struct clk_pll { ...@@ -69,20 +61,19 @@ struct clk_pll {
const struct clk_pll_characteristics *characteristics; const struct clk_pll_characteristics *characteristics;
}; };
static irqreturn_t clk_pll_irq_handler(int irq, void *dev_id) static inline bool clk_pll_ready(struct regmap *regmap, int id)
{ {
struct clk_pll *pll = (struct clk_pll *)dev_id; unsigned int status;
wake_up(&pll->wait); regmap_read(regmap, AT91_PMC_SR, &status);
disable_irq_nosync(pll->irq);
return IRQ_HANDLED; return status & PLL_STATUS_MASK(id) ? 1 : 0;
} }
static int clk_pll_prepare(struct clk_hw *hw) static int clk_pll_prepare(struct clk_hw *hw)
{ {
struct clk_pll *pll = to_clk_pll(hw); struct clk_pll *pll = to_clk_pll(hw);
struct at91_pmc *pmc = pll->pmc; struct regmap *regmap = pll->regmap;
const struct clk_pll_layout *layout = pll->layout; const struct clk_pll_layout *layout = pll->layout;
const struct clk_pll_characteristics *characteristics = const struct clk_pll_characteristics *characteristics =
pll->characteristics; pll->characteristics;
...@@ -90,39 +81,34 @@ static int clk_pll_prepare(struct clk_hw *hw) ...@@ -90,39 +81,34 @@ static int clk_pll_prepare(struct clk_hw *hw)
u32 mask = PLL_STATUS_MASK(id); u32 mask = PLL_STATUS_MASK(id);
int offset = PLL_REG(id); int offset = PLL_REG(id);
u8 out = 0; u8 out = 0;
u32 pllr, icpr; unsigned int pllr;
unsigned int status;
u8 div; u8 div;
u16 mul; u16 mul;
pllr = pmc_read(pmc, offset); regmap_read(regmap, offset, &pllr);
div = PLL_DIV(pllr); div = PLL_DIV(pllr);
mul = PLL_MUL(pllr, layout); mul = PLL_MUL(pllr, layout);
if ((pmc_read(pmc, AT91_PMC_SR) & mask) && regmap_read(regmap, AT91_PMC_SR, &status);
if ((status & mask) &&
(div == pll->div && mul == pll->mul)) (div == pll->div && mul == pll->mul))
return 0; return 0;
if (characteristics->out) if (characteristics->out)
out = characteristics->out[pll->range]; out = characteristics->out[pll->range];
if (characteristics->icpll) {
icpr = pmc_read(pmc, AT91_PMC_PLLICPR) & ~PLL_ICPR_MASK(id);
icpr |= (characteristics->icpll[pll->range] <<
PLL_ICPR_SHIFT(id));
pmc_write(pmc, AT91_PMC_PLLICPR, icpr);
}
pllr &= ~layout->pllr_mask; if (characteristics->icpll)
pllr |= layout->pllr_mask & regmap_update_bits(regmap, AT91_PMC_PLLICPR, PLL_ICPR_MASK(id),
(pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) | characteristics->icpll[pll->range] << PLL_ICPR_SHIFT(id));
(out << PLL_OUT_SHIFT) |
((pll->mul & layout->mul_mask) << layout->mul_shift)); regmap_update_bits(regmap, offset, layout->pllr_mask,
pmc_write(pmc, offset, pllr); pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) |
(out << PLL_OUT_SHIFT) |
while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) { ((pll->mul & layout->mul_mask) << layout->mul_shift));
enable_irq(pll->irq);
wait_event(pll->wait, while (!clk_pll_ready(regmap, pll->id))
pmc_read(pmc, AT91_PMC_SR) & mask); cpu_relax();
}
return 0; return 0;
} }
...@@ -130,32 +116,35 @@ static int clk_pll_prepare(struct clk_hw *hw) ...@@ -130,32 +116,35 @@ static int clk_pll_prepare(struct clk_hw *hw)
static int clk_pll_is_prepared(struct clk_hw *hw) static int clk_pll_is_prepared(struct clk_hw *hw)
{ {
struct clk_pll *pll = to_clk_pll(hw); struct clk_pll *pll = to_clk_pll(hw);
struct at91_pmc *pmc = pll->pmc;
return !!(pmc_read(pmc, AT91_PMC_SR) & return clk_pll_ready(pll->regmap, pll->id);
PLL_STATUS_MASK(pll->id));
} }
static void clk_pll_unprepare(struct clk_hw *hw) static void clk_pll_unprepare(struct clk_hw *hw)
{ {
struct clk_pll *pll = to_clk_pll(hw); struct clk_pll *pll = to_clk_pll(hw);
struct at91_pmc *pmc = pll->pmc; unsigned int mask = pll->layout->pllr_mask;
const struct clk_pll_layout *layout = pll->layout;
int offset = PLL_REG(pll->id);
u32 tmp = pmc_read(pmc, offset) & ~(layout->pllr_mask);
pmc_write(pmc, offset, tmp); regmap_update_bits(pll->regmap, PLL_REG(pll->id), mask, ~mask);
} }
static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_pll *pll = to_clk_pll(hw); struct clk_pll *pll = to_clk_pll(hw);
unsigned int pllr;
u16 mul;
u8 div;
if (!pll->div || !pll->mul) regmap_read(pll->regmap, PLL_REG(pll->id), &pllr);
div = PLL_DIV(pllr);
mul = PLL_MUL(pllr, pll->layout);
if (!div || !mul)
return 0; return 0;
return (parent_rate / pll->div) * (pll->mul + 1); return (parent_rate / div) * (mul + 1);
} }
static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate, static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,
...@@ -308,7 +297,7 @@ static const struct clk_ops pll_ops = { ...@@ -308,7 +297,7 @@ static const struct clk_ops pll_ops = {
}; };
static struct clk * __init static struct clk * __init
at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name, at91_clk_register_pll(struct regmap *regmap, const char *name,
const char *parent_name, u8 id, const char *parent_name, u8 id,
const struct clk_pll_layout *layout, const struct clk_pll_layout *layout,
const struct clk_pll_characteristics *characteristics) const struct clk_pll_characteristics *characteristics)
...@@ -316,9 +305,8 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name, ...@@ -316,9 +305,8 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
struct clk_pll *pll; struct clk_pll *pll;
struct clk *clk = NULL; struct clk *clk = NULL;
struct clk_init_data init; struct clk_init_data init;
int ret;
int offset = PLL_REG(id); int offset = PLL_REG(id);
u32 tmp; unsigned int pllr;
if (id > PLL_MAX_ID) if (id > PLL_MAX_ID)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -337,23 +325,13 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name, ...@@ -337,23 +325,13 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
pll->hw.init = &init; pll->hw.init = &init;
pll->layout = layout; pll->layout = layout;
pll->characteristics = characteristics; pll->characteristics = characteristics;
pll->pmc = pmc; pll->regmap = regmap;
pll->irq = irq; regmap_read(regmap, offset, &pllr);
tmp = pmc_read(pmc, offset) & layout->pllr_mask; pll->div = PLL_DIV(pllr);
pll->div = PLL_DIV(tmp); pll->mul = PLL_MUL(pllr, layout);
pll->mul = PLL_MUL(tmp, layout);
init_waitqueue_head(&pll->wait);
irq_set_status_flags(pll->irq, IRQ_NOAUTOEN);
ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH,
id ? "clk-pllb" : "clk-plla", pll);
if (ret) {
kfree(pll);
return ERR_PTR(ret);
}
clk = clk_register(NULL, &pll->hw); clk = clk_register(NULL, &pll->hw);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
free_irq(pll->irq, pll);
kfree(pll); kfree(pll);
} }
...@@ -483,12 +461,12 @@ of_at91_clk_pll_get_characteristics(struct device_node *np) ...@@ -483,12 +461,12 @@ of_at91_clk_pll_get_characteristics(struct device_node *np)
} }
static void __init static void __init
of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc, of_at91_clk_pll_setup(struct device_node *np,
const struct clk_pll_layout *layout) const struct clk_pll_layout *layout)
{ {
u32 id; u32 id;
unsigned int irq;
struct clk *clk; struct clk *clk;
struct regmap *regmap;
const char *parent_name; const char *parent_name;
const char *name = np->name; const char *name = np->name;
struct clk_pll_characteristics *characteristics; struct clk_pll_characteristics *characteristics;
...@@ -500,15 +478,15 @@ of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc, ...@@ -500,15 +478,15 @@ of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc,
of_property_read_string(np, "clock-output-names", &name); of_property_read_string(np, "clock-output-names", &name);
characteristics = of_at91_clk_pll_get_characteristics(np); regmap = syscon_node_to_regmap(of_get_parent(np));
if (!characteristics) if (IS_ERR(regmap))
return; return;
irq = irq_of_parse_and_map(np, 0); characteristics = of_at91_clk_pll_get_characteristics(np);
if (!irq) if (!characteristics)
return; return;
clk = at91_clk_register_pll(pmc, irq, name, parent_name, id, layout, clk = at91_clk_register_pll(regmap, name, parent_name, id, layout,
characteristics); characteristics);
if (IS_ERR(clk)) if (IS_ERR(clk))
goto out_free_characteristics; goto out_free_characteristics;
...@@ -520,26 +498,30 @@ of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc, ...@@ -520,26 +498,30 @@ of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc,
kfree(characteristics); kfree(characteristics);
} }
void __init of_at91rm9200_clk_pll_setup(struct device_node *np, static void __init of_at91rm9200_clk_pll_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
of_at91_clk_pll_setup(np, pmc, &at91rm9200_pll_layout); of_at91_clk_pll_setup(np, &at91rm9200_pll_layout);
} }
CLK_OF_DECLARE(at91rm9200_clk_pll, "atmel,at91rm9200-clk-pll",
of_at91rm9200_clk_pll_setup);
void __init of_at91sam9g45_clk_pll_setup(struct device_node *np, static void __init of_at91sam9g45_clk_pll_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
of_at91_clk_pll_setup(np, pmc, &at91sam9g45_pll_layout); of_at91_clk_pll_setup(np, &at91sam9g45_pll_layout);
} }
CLK_OF_DECLARE(at91sam9g45_clk_pll, "atmel,at91sam9g45-clk-pll",
of_at91sam9g45_clk_pll_setup);
void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np, static void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
of_at91_clk_pll_setup(np, pmc, &at91sam9g20_pllb_layout); of_at91_clk_pll_setup(np, &at91sam9g20_pllb_layout);
} }
CLK_OF_DECLARE(at91sam9g20_clk_pllb, "atmel,at91sam9g20-clk-pllb",
of_at91sam9g20_clk_pllb_setup);
void __init of_sama5d3_clk_pll_setup(struct device_node *np, static void __init of_sama5d3_clk_pll_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
of_at91_clk_pll_setup(np, pmc, &sama5d3_pll_layout); of_at91_clk_pll_setup(np, &sama5d3_pll_layout);
} }
CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll",
of_sama5d3_clk_pll_setup);
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h> #include <linux/clk/at91_pmc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/mfd/syscon.h>
#include <linux/io.h> #include <linux/regmap.h>
#include "pmc.h" #include "pmc.h"
...@@ -21,16 +21,18 @@ ...@@ -21,16 +21,18 @@
struct clk_plldiv { struct clk_plldiv {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct regmap *regmap;
}; };
static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw, static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_plldiv *plldiv = to_clk_plldiv(hw); struct clk_plldiv *plldiv = to_clk_plldiv(hw);
struct at91_pmc *pmc = plldiv->pmc; unsigned int mckr;
if (pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_PLLADIV2) regmap_read(plldiv->regmap, AT91_PMC_MCKR, &mckr);
if (mckr & AT91_PMC_PLLADIV2)
return parent_rate / 2; return parent_rate / 2;
return parent_rate; return parent_rate;
...@@ -57,18 +59,12 @@ static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -57,18 +59,12 @@ static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_plldiv *plldiv = to_clk_plldiv(hw); struct clk_plldiv *plldiv = to_clk_plldiv(hw);
struct at91_pmc *pmc = plldiv->pmc;
u32 tmp;
if (parent_rate != rate && (parent_rate / 2) != rate) if ((parent_rate != rate) && (parent_rate / 2 != rate))
return -EINVAL; return -EINVAL;
pmc_lock(pmc); regmap_update_bits(plldiv->regmap, AT91_PMC_MCKR, AT91_PMC_PLLADIV2,
tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_PLLADIV2; parent_rate != rate ? AT91_PMC_PLLADIV2 : 0);
if ((parent_rate / 2) == rate)
tmp |= AT91_PMC_PLLADIV2;
pmc_write(pmc, AT91_PMC_MCKR, tmp);
pmc_unlock(pmc);
return 0; return 0;
} }
...@@ -80,7 +76,7 @@ static const struct clk_ops plldiv_ops = { ...@@ -80,7 +76,7 @@ static const struct clk_ops plldiv_ops = {
}; };
static struct clk * __init static struct clk * __init
at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name, at91_clk_register_plldiv(struct regmap *regmap, const char *name,
const char *parent_name) const char *parent_name)
{ {
struct clk_plldiv *plldiv; struct clk_plldiv *plldiv;
...@@ -98,7 +94,7 @@ at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name, ...@@ -98,7 +94,7 @@ at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name,
init.flags = CLK_SET_RATE_GATE; init.flags = CLK_SET_RATE_GATE;
plldiv->hw.init = &init; plldiv->hw.init = &init;
plldiv->pmc = pmc; plldiv->regmap = regmap;
clk = clk_register(NULL, &plldiv->hw); clk = clk_register(NULL, &plldiv->hw);
...@@ -109,27 +105,27 @@ at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name, ...@@ -109,27 +105,27 @@ at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name,
} }
static void __init static void __init
of_at91_clk_plldiv_setup(struct device_node *np, struct at91_pmc *pmc) of_at91sam9x5_clk_plldiv_setup(struct device_node *np)
{ {
struct clk *clk; struct clk *clk;
const char *parent_name; const char *parent_name;
const char *name = np->name; const char *name = np->name;
struct regmap *regmap;
parent_name = of_clk_get_parent_name(np, 0); parent_name = of_clk_get_parent_name(np, 0);
of_property_read_string(np, "clock-output-names", &name); of_property_read_string(np, "clock-output-names", &name);
clk = at91_clk_register_plldiv(pmc, name, parent_name); regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
clk = at91_clk_register_plldiv(regmap, name, parent_name);
if (IS_ERR(clk)) if (IS_ERR(clk))
return; return;
of_clk_add_provider(np, of_clk_src_simple_get, clk); of_clk_add_provider(np, of_clk_src_simple_get, clk);
return; return;
} }
CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv",
void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np, of_at91sam9x5_clk_plldiv_setup);
struct at91_pmc *pmc)
{
of_at91_clk_plldiv_setup(np, pmc);
}
...@@ -12,10 +12,8 @@ ...@@ -12,10 +12,8 @@
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h> #include <linux/clk/at91_pmc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/mfd/syscon.h>
#include <linux/io.h> #include <linux/regmap.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include "pmc.h" #include "pmc.h"
...@@ -24,6 +22,7 @@ ...@@ -24,6 +22,7 @@
#define PROG_STATUS_MASK(id) (1 << ((id) + 8)) #define PROG_STATUS_MASK(id) (1 << ((id) + 8))
#define PROG_PRES_MASK 0x7 #define PROG_PRES_MASK 0x7
#define PROG_PRES(layout, pckr) ((pckr >> layout->pres_shift) & PROG_PRES_MASK)
#define PROG_MAX_RM9200_CSS 3 #define PROG_MAX_RM9200_CSS 3
struct clk_programmable_layout { struct clk_programmable_layout {
...@@ -34,7 +33,7 @@ struct clk_programmable_layout { ...@@ -34,7 +33,7 @@ struct clk_programmable_layout {
struct clk_programmable { struct clk_programmable {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct regmap *regmap;
u8 id; u8 id;
const struct clk_programmable_layout *layout; const struct clk_programmable_layout *layout;
}; };
...@@ -44,14 +43,12 @@ struct clk_programmable { ...@@ -44,14 +43,12 @@ struct clk_programmable {
static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw, static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
u32 pres;
struct clk_programmable *prog = to_clk_programmable(hw); struct clk_programmable *prog = to_clk_programmable(hw);
struct at91_pmc *pmc = prog->pmc; unsigned int pckr;
const struct clk_programmable_layout *layout = prog->layout;
regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
pres = (pmc_read(pmc, AT91_PMC_PCKR(prog->id)) >> layout->pres_shift) & return parent_rate >> PROG_PRES(prog->layout, pckr);
PROG_PRES_MASK;
return parent_rate >> pres;
} }
static int clk_programmable_determine_rate(struct clk_hw *hw, static int clk_programmable_determine_rate(struct clk_hw *hw,
...@@ -101,36 +98,36 @@ static int clk_programmable_set_parent(struct clk_hw *hw, u8 index) ...@@ -101,36 +98,36 @@ static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
{ {
struct clk_programmable *prog = to_clk_programmable(hw); struct clk_programmable *prog = to_clk_programmable(hw);
const struct clk_programmable_layout *layout = prog->layout; const struct clk_programmable_layout *layout = prog->layout;
struct at91_pmc *pmc = prog->pmc; unsigned int mask = layout->css_mask;
u32 tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)) & ~layout->css_mask; unsigned int pckr = 0;
if (layout->have_slck_mck) if (layout->have_slck_mck)
tmp &= AT91_PMC_CSSMCK_MCK; mask |= AT91_PMC_CSSMCK_MCK;
if (index > layout->css_mask) { if (index > layout->css_mask) {
if (index > PROG_MAX_RM9200_CSS && layout->have_slck_mck) { if (index > PROG_MAX_RM9200_CSS && !layout->have_slck_mck)
tmp |= AT91_PMC_CSSMCK_MCK;
return 0;
} else {
return -EINVAL; return -EINVAL;
}
pckr |= AT91_PMC_CSSMCK_MCK;
} }
pmc_write(pmc, AT91_PMC_PCKR(prog->id), tmp | index); regmap_update_bits(prog->regmap, AT91_PMC_PCKR(prog->id), mask, pckr);
return 0; return 0;
} }
static u8 clk_programmable_get_parent(struct clk_hw *hw) static u8 clk_programmable_get_parent(struct clk_hw *hw)
{ {
u32 tmp;
u8 ret;
struct clk_programmable *prog = to_clk_programmable(hw); struct clk_programmable *prog = to_clk_programmable(hw);
struct at91_pmc *pmc = prog->pmc;
const struct clk_programmable_layout *layout = prog->layout; const struct clk_programmable_layout *layout = prog->layout;
unsigned int pckr;
u8 ret;
regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
ret = pckr & layout->css_mask;
tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)); if (layout->have_slck_mck && (pckr & AT91_PMC_CSSMCK_MCK) && !ret)
ret = tmp & layout->css_mask;
if (layout->have_slck_mck && (tmp & AT91_PMC_CSSMCK_MCK) && !ret)
ret = PROG_MAX_RM9200_CSS + 1; ret = PROG_MAX_RM9200_CSS + 1;
return ret; return ret;
...@@ -140,26 +137,27 @@ static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -140,26 +137,27 @@ static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_programmable *prog = to_clk_programmable(hw); struct clk_programmable *prog = to_clk_programmable(hw);
struct at91_pmc *pmc = prog->pmc;
const struct clk_programmable_layout *layout = prog->layout; const struct clk_programmable_layout *layout = prog->layout;
unsigned long div = parent_rate / rate; unsigned long div = parent_rate / rate;
unsigned int pckr;
int shift = 0; int shift = 0;
u32 tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)) &
~(PROG_PRES_MASK << layout->pres_shift); regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
if (!div) if (!div)
return -EINVAL; return -EINVAL;
shift = fls(div) - 1; shift = fls(div) - 1;
if (div != (1<<shift)) if (div != (1 << shift))
return -EINVAL; return -EINVAL;
if (shift >= PROG_PRES_MASK) if (shift >= PROG_PRES_MASK)
return -EINVAL; return -EINVAL;
pmc_write(pmc, AT91_PMC_PCKR(prog->id), regmap_update_bits(prog->regmap, AT91_PMC_PCKR(prog->id),
tmp | (shift << layout->pres_shift)); PROG_PRES_MASK << layout->pres_shift,
shift << layout->pres_shift);
return 0; return 0;
} }
...@@ -173,7 +171,7 @@ static const struct clk_ops programmable_ops = { ...@@ -173,7 +171,7 @@ static const struct clk_ops programmable_ops = {
}; };
static struct clk * __init static struct clk * __init
at91_clk_register_programmable(struct at91_pmc *pmc, at91_clk_register_programmable(struct regmap *regmap,
const char *name, const char **parent_names, const char *name, const char **parent_names,
u8 num_parents, u8 id, u8 num_parents, u8 id,
const struct clk_programmable_layout *layout) const struct clk_programmable_layout *layout)
...@@ -198,7 +196,7 @@ at91_clk_register_programmable(struct at91_pmc *pmc, ...@@ -198,7 +196,7 @@ at91_clk_register_programmable(struct at91_pmc *pmc,
prog->id = id; prog->id = id;
prog->layout = layout; prog->layout = layout;
prog->hw.init = &init; prog->hw.init = &init;
prog->pmc = pmc; prog->regmap = regmap;
clk = clk_register(NULL, &prog->hw); clk = clk_register(NULL, &prog->hw);
if (IS_ERR(clk)) if (IS_ERR(clk))
...@@ -226,7 +224,7 @@ static const struct clk_programmable_layout at91sam9x5_programmable_layout = { ...@@ -226,7 +224,7 @@ static const struct clk_programmable_layout at91sam9x5_programmable_layout = {
}; };
static void __init static void __init
of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, of_at91_clk_prog_setup(struct device_node *np,
const struct clk_programmable_layout *layout) const struct clk_programmable_layout *layout)
{ {
int num; int num;
...@@ -236,6 +234,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, ...@@ -236,6 +234,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
const char *parent_names[PROG_SOURCE_MAX]; const char *parent_names[PROG_SOURCE_MAX];
const char *name; const char *name;
struct device_node *progclknp; struct device_node *progclknp;
struct regmap *regmap;
num_parents = of_clk_get_parent_count(np); num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX) if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX)
...@@ -247,6 +246,10 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, ...@@ -247,6 +246,10 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
if (!num || num > (PROG_ID_MAX + 1)) if (!num || num > (PROG_ID_MAX + 1))
return; return;
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
for_each_child_of_node(np, progclknp) { for_each_child_of_node(np, progclknp) {
if (of_property_read_u32(progclknp, "reg", &id)) if (of_property_read_u32(progclknp, "reg", &id))
continue; continue;
...@@ -254,7 +257,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, ...@@ -254,7 +257,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
if (of_property_read_string(np, "clock-output-names", &name)) if (of_property_read_string(np, "clock-output-names", &name))
name = progclknp->name; name = progclknp->name;
clk = at91_clk_register_programmable(pmc, name, clk = at91_clk_register_programmable(regmap, name,
parent_names, num_parents, parent_names, num_parents,
id, layout); id, layout);
if (IS_ERR(clk)) if (IS_ERR(clk))
...@@ -265,20 +268,23 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, ...@@ -265,20 +268,23 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
} }
void __init of_at91rm9200_clk_prog_setup(struct device_node *np, static void __init of_at91rm9200_clk_prog_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
of_at91_clk_prog_setup(np, pmc, &at91rm9200_programmable_layout); of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout);
} }
CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable",
of_at91rm9200_clk_prog_setup);
void __init of_at91sam9g45_clk_prog_setup(struct device_node *np, static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
of_at91_clk_prog_setup(np, pmc, &at91sam9g45_programmable_layout); of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout);
} }
CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable",
of_at91sam9g45_clk_prog_setup);
void __init of_at91sam9x5_clk_prog_setup(struct device_node *np, static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
of_at91_clk_prog_setup(np, pmc, &at91sam9x5_programmable_layout); of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout);
} }
CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable",
of_at91sam9x5_clk_prog_setup);
...@@ -12,17 +12,11 @@ ...@@ -12,17 +12,11 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/slab.h>
#include <linux/clk/at91_pmc.h> #include <linux/clk/at91_pmc.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/mfd/syscon.h>
#include <linux/of_irq.h> #include <linux/regmap.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include "pmc.h" #include "pmc.h"
#include "sckc.h" #include "sckc.h"
...@@ -58,7 +52,7 @@ struct clk_slow_rc_osc { ...@@ -58,7 +52,7 @@ struct clk_slow_rc_osc {
struct clk_sam9260_slow { struct clk_sam9260_slow {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct regmap *regmap;
}; };
#define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw) #define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw)
...@@ -388,8 +382,11 @@ void __init of_at91sam9x5_clk_slow_setup(struct device_node *np, ...@@ -388,8 +382,11 @@ void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw) static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
{ {
struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw); struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw);
unsigned int status;
return !!(pmc_read(slowck->pmc, AT91_PMC_SR) & AT91_PMC_OSCSEL); regmap_read(slowck->regmap, AT91_PMC_SR, &status);
return status & AT91_PMC_OSCSEL ? 1 : 0;
} }
static const struct clk_ops sam9260_slow_ops = { static const struct clk_ops sam9260_slow_ops = {
...@@ -397,7 +394,7 @@ static const struct clk_ops sam9260_slow_ops = { ...@@ -397,7 +394,7 @@ static const struct clk_ops sam9260_slow_ops = {
}; };
static struct clk * __init static struct clk * __init
at91_clk_register_sam9260_slow(struct at91_pmc *pmc, at91_clk_register_sam9260_slow(struct regmap *regmap,
const char *name, const char *name,
const char **parent_names, const char **parent_names,
int num_parents) int num_parents)
...@@ -406,7 +403,7 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc, ...@@ -406,7 +403,7 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
struct clk *clk = NULL; struct clk *clk = NULL;
struct clk_init_data init; struct clk_init_data init;
if (!pmc || !name) if (!name)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (!parent_names || !num_parents) if (!parent_names || !num_parents)
...@@ -423,7 +420,7 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc, ...@@ -423,7 +420,7 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
init.flags = 0; init.flags = 0;
slowck->hw.init = &init; slowck->hw.init = &init;
slowck->pmc = pmc; slowck->regmap = regmap;
clk = clk_register(NULL, &slowck->hw); clk = clk_register(NULL, &slowck->hw);
if (IS_ERR(clk)) if (IS_ERR(clk))
...@@ -432,26 +429,32 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc, ...@@ -432,26 +429,32 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
return clk; return clk;
} }
void __init of_at91sam9260_clk_slow_setup(struct device_node *np, static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
struct clk *clk; struct clk *clk;
const char *parent_names[2]; const char *parent_names[2];
int num_parents; int num_parents;
const char *name = np->name; const char *name = np->name;
struct regmap *regmap;
num_parents = of_clk_get_parent_count(np); num_parents = of_clk_get_parent_count(np);
if (num_parents != 2) if (num_parents != 2)
return; return;
of_clk_parent_fill(np, parent_names, num_parents); of_clk_parent_fill(np, parent_names, num_parents);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
of_property_read_string(np, "clock-output-names", &name); of_property_read_string(np, "clock-output-names", &name);
clk = at91_clk_register_sam9260_slow(pmc, name, parent_names, clk = at91_clk_register_sam9260_slow(regmap, name, parent_names,
num_parents); num_parents);
if (IS_ERR(clk)) if (IS_ERR(clk))
return; return;
of_clk_add_provider(np, of_clk_src_simple_get, clk); of_clk_add_provider(np, of_clk_src_simple_get, clk);
} }
CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
of_at91sam9260_clk_slow_setup);
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h> #include <linux/clk/at91_pmc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/mfd/syscon.h>
#include <linux/io.h> #include <linux/regmap.h>
#include "pmc.h" #include "pmc.h"
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
struct at91sam9x5_clk_smd { struct at91sam9x5_clk_smd {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct regmap *regmap;
}; };
#define to_at91sam9x5_clk_smd(hw) \ #define to_at91sam9x5_clk_smd(hw) \
...@@ -33,13 +33,13 @@ struct at91sam9x5_clk_smd { ...@@ -33,13 +33,13 @@ struct at91sam9x5_clk_smd {
static unsigned long at91sam9x5_clk_smd_recalc_rate(struct clk_hw *hw, static unsigned long at91sam9x5_clk_smd_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
u32 tmp;
u8 smddiv;
struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
struct at91_pmc *pmc = smd->pmc; unsigned int smdr;
u8 smddiv;
regmap_read(smd->regmap, AT91_PMC_SMD, &smdr);
smddiv = (smdr & AT91_PMC_SMD_DIV) >> SMD_DIV_SHIFT;
tmp = pmc_read(pmc, AT91_PMC_SMD);
smddiv = (tmp & AT91_PMC_SMD_DIV) >> SMD_DIV_SHIFT;
return parent_rate / (smddiv + 1); return parent_rate / (smddiv + 1);
} }
...@@ -67,40 +67,38 @@ static long at91sam9x5_clk_smd_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -67,40 +67,38 @@ static long at91sam9x5_clk_smd_round_rate(struct clk_hw *hw, unsigned long rate,
static int at91sam9x5_clk_smd_set_parent(struct clk_hw *hw, u8 index) static int at91sam9x5_clk_smd_set_parent(struct clk_hw *hw, u8 index)
{ {
u32 tmp;
struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
struct at91_pmc *pmc = smd->pmc;
if (index > 1) if (index > 1)
return -EINVAL; return -EINVAL;
tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMDS;
if (index) regmap_update_bits(smd->regmap, AT91_PMC_SMD, AT91_PMC_SMDS,
tmp |= AT91_PMC_SMDS; index ? AT91_PMC_SMDS : 0);
pmc_write(pmc, AT91_PMC_SMD, tmp);
return 0; return 0;
} }
static u8 at91sam9x5_clk_smd_get_parent(struct clk_hw *hw) static u8 at91sam9x5_clk_smd_get_parent(struct clk_hw *hw)
{ {
struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
struct at91_pmc *pmc = smd->pmc; unsigned int smdr;
return pmc_read(pmc, AT91_PMC_SMD) & AT91_PMC_SMDS; regmap_read(smd->regmap, AT91_PMC_SMD, &smdr);
return smdr & AT91_PMC_SMDS;
} }
static int at91sam9x5_clk_smd_set_rate(struct clk_hw *hw, unsigned long rate, static int at91sam9x5_clk_smd_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
u32 tmp;
struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw); struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
struct at91_pmc *pmc = smd->pmc;
unsigned long div = parent_rate / rate; unsigned long div = parent_rate / rate;
if (parent_rate % rate || div < 1 || div > (SMD_MAX_DIV + 1)) if (parent_rate % rate || div < 1 || div > (SMD_MAX_DIV + 1))
return -EINVAL; return -EINVAL;
tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMD_DIV;
tmp |= (div - 1) << SMD_DIV_SHIFT; regmap_update_bits(smd->regmap, AT91_PMC_SMD, AT91_PMC_SMD_DIV,
pmc_write(pmc, AT91_PMC_SMD, tmp); (div - 1) << SMD_DIV_SHIFT);
return 0; return 0;
} }
...@@ -114,7 +112,7 @@ static const struct clk_ops at91sam9x5_smd_ops = { ...@@ -114,7 +112,7 @@ static const struct clk_ops at91sam9x5_smd_ops = {
}; };
static struct clk * __init static struct clk * __init
at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name, at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents) const char **parent_names, u8 num_parents)
{ {
struct at91sam9x5_clk_smd *smd; struct at91sam9x5_clk_smd *smd;
...@@ -132,7 +130,7 @@ at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name, ...@@ -132,7 +130,7 @@ at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name,
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
smd->hw.init = &init; smd->hw.init = &init;
smd->pmc = pmc; smd->regmap = regmap;
clk = clk_register(NULL, &smd->hw); clk = clk_register(NULL, &smd->hw);
if (IS_ERR(clk)) if (IS_ERR(clk))
...@@ -141,13 +139,13 @@ at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name, ...@@ -141,13 +139,13 @@ at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name,
return clk; return clk;
} }
void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
struct clk *clk; struct clk *clk;
int num_parents; int num_parents;
const char *parent_names[SMD_SOURCE_MAX]; const char *parent_names[SMD_SOURCE_MAX];
const char *name = np->name; const char *name = np->name;
struct regmap *regmap;
num_parents = of_clk_get_parent_count(np); num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX) if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX)
...@@ -157,10 +155,16 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, ...@@ -157,10 +155,16 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
of_property_read_string(np, "clock-output-names", &name); of_property_read_string(np, "clock-output-names", &name);
clk = at91sam9x5_clk_register_smd(pmc, name, parent_names, regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
clk = at91sam9x5_clk_register_smd(regmap, name, parent_names,
num_parents); num_parents);
if (IS_ERR(clk)) if (IS_ERR(clk))
return; return;
of_clk_add_provider(np, of_clk_src_simple_get, clk); of_clk_add_provider(np, of_clk_src_simple_get, clk);
} }
CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd",
of_at91sam9x5_clk_smd_setup);
...@@ -12,13 +12,8 @@ ...@@ -12,13 +12,8 @@
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h> #include <linux/clk/at91_pmc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/mfd/syscon.h>
#include <linux/io.h> #include <linux/regmap.h>
#include <linux/irq.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include "pmc.h" #include "pmc.h"
...@@ -29,9 +24,7 @@ ...@@ -29,9 +24,7 @@
#define to_clk_system(hw) container_of(hw, struct clk_system, hw) #define to_clk_system(hw) container_of(hw, struct clk_system, hw)
struct clk_system { struct clk_system {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct regmap *regmap;
unsigned int irq;
wait_queue_head_t wait;
u8 id; u8 id;
}; };
...@@ -39,58 +32,54 @@ static inline int is_pck(int id) ...@@ -39,58 +32,54 @@ static inline int is_pck(int id)
{ {
return (id >= 8) && (id <= 15); return (id >= 8) && (id <= 15);
} }
static irqreturn_t clk_system_irq_handler(int irq, void *dev_id)
static inline bool clk_system_ready(struct regmap *regmap, int id)
{ {
struct clk_system *sys = (struct clk_system *)dev_id; unsigned int status;
wake_up(&sys->wait); regmap_read(regmap, AT91_PMC_SR, &status);
disable_irq_nosync(sys->irq);
return IRQ_HANDLED; return status & (1 << id) ? 1 : 0;
} }
static int clk_system_prepare(struct clk_hw *hw) static int clk_system_prepare(struct clk_hw *hw)
{ {
struct clk_system *sys = to_clk_system(hw); struct clk_system *sys = to_clk_system(hw);
struct at91_pmc *pmc = sys->pmc;
u32 mask = 1 << sys->id;
pmc_write(pmc, AT91_PMC_SCER, mask); regmap_write(sys->regmap, AT91_PMC_SCER, 1 << sys->id);
if (!is_pck(sys->id)) if (!is_pck(sys->id))
return 0; return 0;
while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) { while (!clk_system_ready(sys->regmap, sys->id))
if (sys->irq) { cpu_relax();
enable_irq(sys->irq);
wait_event(sys->wait,
pmc_read(pmc, AT91_PMC_SR) & mask);
} else
cpu_relax();
}
return 0; return 0;
} }
static void clk_system_unprepare(struct clk_hw *hw) static void clk_system_unprepare(struct clk_hw *hw)
{ {
struct clk_system *sys = to_clk_system(hw); struct clk_system *sys = to_clk_system(hw);
struct at91_pmc *pmc = sys->pmc;
pmc_write(pmc, AT91_PMC_SCDR, 1 << sys->id); regmap_write(sys->regmap, AT91_PMC_SCDR, 1 << sys->id);
} }
static int clk_system_is_prepared(struct clk_hw *hw) static int clk_system_is_prepared(struct clk_hw *hw)
{ {
struct clk_system *sys = to_clk_system(hw); struct clk_system *sys = to_clk_system(hw);
struct at91_pmc *pmc = sys->pmc; unsigned int status;
regmap_read(sys->regmap, AT91_PMC_SCSR, &status);
if (!(pmc_read(pmc, AT91_PMC_SCSR) & (1 << sys->id))) if (!(status & (1 << sys->id)))
return 0; return 0;
if (!is_pck(sys->id)) if (!is_pck(sys->id))
return 1; return 1;
return !!(pmc_read(pmc, AT91_PMC_SR) & (1 << sys->id)); regmap_read(sys->regmap, AT91_PMC_SR, &status);
return status & (1 << sys->id) ? 1 : 0;
} }
static const struct clk_ops system_ops = { static const struct clk_ops system_ops = {
...@@ -100,13 +89,12 @@ static const struct clk_ops system_ops = { ...@@ -100,13 +89,12 @@ static const struct clk_ops system_ops = {
}; };
static struct clk * __init static struct clk * __init
at91_clk_register_system(struct at91_pmc *pmc, const char *name, at91_clk_register_system(struct regmap *regmap, const char *name,
const char *parent_name, u8 id, int irq) const char *parent_name, u8 id)
{ {
struct clk_system *sys; struct clk_system *sys;
struct clk *clk = NULL; struct clk *clk = NULL;
struct clk_init_data init; struct clk_init_data init;
int ret;
if (!parent_name || id > SYSTEM_MAX_ID) if (!parent_name || id > SYSTEM_MAX_ID)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -123,44 +111,33 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name, ...@@ -123,44 +111,33 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name,
sys->id = id; sys->id = id;
sys->hw.init = &init; sys->hw.init = &init;
sys->pmc = pmc; sys->regmap = regmap;
sys->irq = irq;
if (irq) {
init_waitqueue_head(&sys->wait);
irq_set_status_flags(sys->irq, IRQ_NOAUTOEN);
ret = request_irq(sys->irq, clk_system_irq_handler,
IRQF_TRIGGER_HIGH, name, sys);
if (ret) {
kfree(sys);
return ERR_PTR(ret);
}
}
clk = clk_register(NULL, &sys->hw); clk = clk_register(NULL, &sys->hw);
if (IS_ERR(clk)) { if (IS_ERR(clk))
if (irq)
free_irq(sys->irq, sys);
kfree(sys); kfree(sys);
}
return clk; return clk;
} }
static void __init static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc)
{ {
int num; int num;
int irq = 0;
u32 id; u32 id;
struct clk *clk; struct clk *clk;
const char *name; const char *name;
struct device_node *sysclknp; struct device_node *sysclknp;
const char *parent_name; const char *parent_name;
struct regmap *regmap;
num = of_get_child_count(np); num = of_get_child_count(np);
if (num > (SYSTEM_MAX_ID + 1)) if (num > (SYSTEM_MAX_ID + 1))
return; return;
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
for_each_child_of_node(np, sysclknp) { for_each_child_of_node(np, sysclknp) {
if (of_property_read_u32(sysclknp, "reg", &id)) if (of_property_read_u32(sysclknp, "reg", &id))
continue; continue;
...@@ -168,21 +145,14 @@ of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc) ...@@ -168,21 +145,14 @@ of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc)
if (of_property_read_string(np, "clock-output-names", &name)) if (of_property_read_string(np, "clock-output-names", &name))
name = sysclknp->name; name = sysclknp->name;
if (is_pck(id))
irq = irq_of_parse_and_map(sysclknp, 0);
parent_name = of_clk_get_parent_name(sysclknp, 0); parent_name = of_clk_get_parent_name(sysclknp, 0);
clk = at91_clk_register_system(pmc, name, parent_name, id, irq); clk = at91_clk_register_system(regmap, name, parent_name, id);
if (IS_ERR(clk)) if (IS_ERR(clk))
continue; continue;
of_clk_add_provider(sysclknp, of_clk_src_simple_get, clk); of_clk_add_provider(sysclknp, of_clk_src_simple_get, clk);
} }
} }
CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system",
void __init of_at91rm9200_clk_sys_setup(struct device_node *np, of_at91rm9200_clk_sys_setup);
struct at91_pmc *pmc)
{
of_at91_clk_sys_setup(np, pmc);
}
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h> #include <linux/clk/at91_pmc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/mfd/syscon.h>
#include <linux/io.h> #include <linux/regmap.h>
#include "pmc.h" #include "pmc.h"
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
struct at91sam9x5_clk_usb { struct at91sam9x5_clk_usb {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct regmap *regmap;
}; };
#define to_at91sam9x5_clk_usb(hw) \ #define to_at91sam9x5_clk_usb(hw) \
...@@ -35,7 +35,7 @@ struct at91sam9x5_clk_usb { ...@@ -35,7 +35,7 @@ struct at91sam9x5_clk_usb {
struct at91rm9200_clk_usb { struct at91rm9200_clk_usb {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct regmap *regmap;
u32 divisors[4]; u32 divisors[4];
}; };
...@@ -45,13 +45,12 @@ struct at91rm9200_clk_usb { ...@@ -45,13 +45,12 @@ struct at91rm9200_clk_usb {
static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw, static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
u32 tmp;
u8 usbdiv;
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc; unsigned int usbr;
u8 usbdiv;
tmp = pmc_read(pmc, AT91_PMC_USB); regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT; usbdiv = (usbr & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT;
return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1)); return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1));
} }
...@@ -109,33 +108,31 @@ static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, ...@@ -109,33 +108,31 @@ static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
{ {
u32 tmp;
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
if (index > 1) if (index > 1)
return -EINVAL; return -EINVAL;
tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS;
if (index) regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS,
tmp |= AT91_PMC_USBS; index ? AT91_PMC_USBS : 0);
pmc_write(pmc, AT91_PMC_USB, tmp);
return 0; return 0;
} }
static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw) static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw)
{ {
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc; unsigned int usbr;
return pmc_read(pmc, AT91_PMC_USB) & AT91_PMC_USBS; regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
return usbr & AT91_PMC_USBS;
} }
static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
u32 tmp;
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
unsigned long div; unsigned long div;
if (!rate) if (!rate)
...@@ -145,9 +142,8 @@ static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -145,9 +142,8 @@ static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
if (div > SAM9X5_USB_MAX_DIV + 1 || !div) if (div > SAM9X5_USB_MAX_DIV + 1 || !div)
return -EINVAL; return -EINVAL;
tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV; regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_OHCIUSBDIV,
tmp |= (div - 1) << SAM9X5_USB_DIV_SHIFT; (div - 1) << SAM9X5_USB_DIV_SHIFT);
pmc_write(pmc, AT91_PMC_USB, tmp);
return 0; return 0;
} }
...@@ -163,28 +159,28 @@ static const struct clk_ops at91sam9x5_usb_ops = { ...@@ -163,28 +159,28 @@ static const struct clk_ops at91sam9x5_usb_ops = {
static int at91sam9n12_clk_usb_enable(struct clk_hw *hw) static int at91sam9n12_clk_usb_enable(struct clk_hw *hw)
{ {
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
pmc_write(pmc, AT91_PMC_USB, regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS,
pmc_read(pmc, AT91_PMC_USB) | AT91_PMC_USBS); AT91_PMC_USBS);
return 0; return 0;
} }
static void at91sam9n12_clk_usb_disable(struct clk_hw *hw) static void at91sam9n12_clk_usb_disable(struct clk_hw *hw)
{ {
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
pmc_write(pmc, AT91_PMC_USB, regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS, 0);
pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS);
} }
static int at91sam9n12_clk_usb_is_enabled(struct clk_hw *hw) static int at91sam9n12_clk_usb_is_enabled(struct clk_hw *hw)
{ {
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc; unsigned int usbr;
return !!(pmc_read(pmc, AT91_PMC_USB) & AT91_PMC_USBS); regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
return usbr & AT91_PMC_USBS;
} }
static const struct clk_ops at91sam9n12_usb_ops = { static const struct clk_ops at91sam9n12_usb_ops = {
...@@ -197,7 +193,7 @@ static const struct clk_ops at91sam9n12_usb_ops = { ...@@ -197,7 +193,7 @@ static const struct clk_ops at91sam9n12_usb_ops = {
}; };
static struct clk * __init static struct clk * __init
at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name, at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents) const char **parent_names, u8 num_parents)
{ {
struct at91sam9x5_clk_usb *usb; struct at91sam9x5_clk_usb *usb;
...@@ -216,7 +212,7 @@ at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name, ...@@ -216,7 +212,7 @@ at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name,
CLK_SET_RATE_PARENT; CLK_SET_RATE_PARENT;
usb->hw.init = &init; usb->hw.init = &init;
usb->pmc = pmc; usb->regmap = regmap;
clk = clk_register(NULL, &usb->hw); clk = clk_register(NULL, &usb->hw);
if (IS_ERR(clk)) if (IS_ERR(clk))
...@@ -226,7 +222,7 @@ at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name, ...@@ -226,7 +222,7 @@ at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name,
} }
static struct clk * __init static struct clk * __init
at91sam9n12_clk_register_usb(struct at91_pmc *pmc, const char *name, at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,
const char *parent_name) const char *parent_name)
{ {
struct at91sam9x5_clk_usb *usb; struct at91sam9x5_clk_usb *usb;
...@@ -244,7 +240,7 @@ at91sam9n12_clk_register_usb(struct at91_pmc *pmc, const char *name, ...@@ -244,7 +240,7 @@ at91sam9n12_clk_register_usb(struct at91_pmc *pmc, const char *name,
init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT;
usb->hw.init = &init; usb->hw.init = &init;
usb->pmc = pmc; usb->regmap = regmap;
clk = clk_register(NULL, &usb->hw); clk = clk_register(NULL, &usb->hw);
if (IS_ERR(clk)) if (IS_ERR(clk))
...@@ -257,12 +253,12 @@ static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw, ...@@ -257,12 +253,12 @@ static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc; unsigned int pllbr;
u32 tmp;
u8 usbdiv; u8 usbdiv;
tmp = pmc_read(pmc, AT91_CKGR_PLLBR); regmap_read(usb->regmap, AT91_CKGR_PLLBR, &pllbr);
usbdiv = (tmp & AT91_PMC_USBDIV) >> RM9200_USB_DIV_SHIFT;
usbdiv = (pllbr & AT91_PMC_USBDIV) >> RM9200_USB_DIV_SHIFT;
if (usb->divisors[usbdiv]) if (usb->divisors[usbdiv])
return parent_rate / usb->divisors[usbdiv]; return parent_rate / usb->divisors[usbdiv];
...@@ -310,10 +306,8 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -310,10 +306,8 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
u32 tmp;
int i; int i;
struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw); struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
unsigned long div; unsigned long div;
if (!rate) if (!rate)
...@@ -323,10 +317,10 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -323,10 +317,10 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
if (usb->divisors[i] == div) { if (usb->divisors[i] == div) {
tmp = pmc_read(pmc, AT91_CKGR_PLLBR) & regmap_update_bits(usb->regmap, AT91_CKGR_PLLBR,
~AT91_PMC_USBDIV; AT91_PMC_USBDIV,
tmp |= i << RM9200_USB_DIV_SHIFT; i << RM9200_USB_DIV_SHIFT);
pmc_write(pmc, AT91_CKGR_PLLBR, tmp);
return 0; return 0;
} }
} }
...@@ -341,7 +335,7 @@ static const struct clk_ops at91rm9200_usb_ops = { ...@@ -341,7 +335,7 @@ static const struct clk_ops at91rm9200_usb_ops = {
}; };
static struct clk * __init static struct clk * __init
at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name, at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,
const char *parent_name, const u32 *divisors) const char *parent_name, const u32 *divisors)
{ {
struct at91rm9200_clk_usb *usb; struct at91rm9200_clk_usb *usb;
...@@ -359,7 +353,7 @@ at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name, ...@@ -359,7 +353,7 @@ at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name,
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
usb->hw.init = &init; usb->hw.init = &init;
usb->pmc = pmc; usb->regmap = regmap;
memcpy(usb->divisors, divisors, sizeof(usb->divisors)); memcpy(usb->divisors, divisors, sizeof(usb->divisors));
clk = clk_register(NULL, &usb->hw); clk = clk_register(NULL, &usb->hw);
...@@ -369,13 +363,13 @@ at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name, ...@@ -369,13 +363,13 @@ at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name,
return clk; return clk;
} }
void __init of_at91sam9x5_clk_usb_setup(struct device_node *np, static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
struct clk *clk; struct clk *clk;
int num_parents; int num_parents;
const char *parent_names[USB_SOURCE_MAX]; const char *parent_names[USB_SOURCE_MAX];
const char *name = np->name; const char *name = np->name;
struct regmap *regmap;
num_parents = of_clk_get_parent_count(np); num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > USB_SOURCE_MAX) if (num_parents <= 0 || num_parents > USB_SOURCE_MAX)
...@@ -385,19 +379,26 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np, ...@@ -385,19 +379,26 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
of_property_read_string(np, "clock-output-names", &name); of_property_read_string(np, "clock-output-names", &name);
clk = at91sam9x5_clk_register_usb(pmc, name, parent_names, num_parents); regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
clk = at91sam9x5_clk_register_usb(regmap, name, parent_names,
num_parents);
if (IS_ERR(clk)) if (IS_ERR(clk))
return; return;
of_clk_add_provider(np, of_clk_src_simple_get, clk); of_clk_add_provider(np, of_clk_src_simple_get, clk);
} }
CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb",
of_at91sam9x5_clk_usb_setup);
void __init of_at91sam9n12_clk_usb_setup(struct device_node *np, static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
struct clk *clk; struct clk *clk;
const char *parent_name; const char *parent_name;
const char *name = np->name; const char *name = np->name;
struct regmap *regmap;
parent_name = of_clk_get_parent_name(np, 0); parent_name = of_clk_get_parent_name(np, 0);
if (!parent_name) if (!parent_name)
...@@ -405,20 +406,26 @@ void __init of_at91sam9n12_clk_usb_setup(struct device_node *np, ...@@ -405,20 +406,26 @@ void __init of_at91sam9n12_clk_usb_setup(struct device_node *np,
of_property_read_string(np, "clock-output-names", &name); of_property_read_string(np, "clock-output-names", &name);
clk = at91sam9n12_clk_register_usb(pmc, name, parent_name); regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
clk = at91sam9n12_clk_register_usb(regmap, name, parent_name);
if (IS_ERR(clk)) if (IS_ERR(clk))
return; return;
of_clk_add_provider(np, of_clk_src_simple_get, clk); of_clk_add_provider(np, of_clk_src_simple_get, clk);
} }
CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb",
of_at91sam9n12_clk_usb_setup);
void __init of_at91rm9200_clk_usb_setup(struct device_node *np, static void __init of_at91rm9200_clk_usb_setup(struct device_node *np)
struct at91_pmc *pmc)
{ {
struct clk *clk; struct clk *clk;
const char *parent_name; const char *parent_name;
const char *name = np->name; const char *name = np->name;
u32 divisors[4] = {0, 0, 0, 0}; u32 divisors[4] = {0, 0, 0, 0};
struct regmap *regmap;
parent_name = of_clk_get_parent_name(np, 0); parent_name = of_clk_get_parent_name(np, 0);
if (!parent_name) if (!parent_name)
...@@ -430,9 +437,15 @@ void __init of_at91rm9200_clk_usb_setup(struct device_node *np, ...@@ -430,9 +437,15 @@ void __init of_at91rm9200_clk_usb_setup(struct device_node *np,
of_property_read_string(np, "clock-output-names", &name); of_property_read_string(np, "clock-output-names", &name);
clk = at91rm9200_clk_register_usb(pmc, name, parent_name, divisors); regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
clk = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors);
if (IS_ERR(clk)) if (IS_ERR(clk))
return; return;
of_clk_add_provider(np, of_clk_src_simple_get, clk); of_clk_add_provider(np, of_clk_src_simple_get, clk);
} }
CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb",
of_at91rm9200_clk_usb_setup);
...@@ -11,14 +11,9 @@ ...@@ -11,14 +11,9 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h> #include <linux/clk/at91_pmc.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/mfd/syscon.h>
#include <linux/of_irq.h> #include <linux/regmap.h>
#include <linux/io.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include "pmc.h" #include "pmc.h"
...@@ -26,37 +21,30 @@ ...@@ -26,37 +21,30 @@
struct clk_utmi { struct clk_utmi {
struct clk_hw hw; struct clk_hw hw;
struct at91_pmc *pmc; struct regmap *regmap;
unsigned int irq;
wait_queue_head_t wait;
}; };
#define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw) #define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw)
static irqreturn_t clk_utmi_irq_handler(int irq, void *dev_id) static inline bool clk_utmi_ready(struct regmap *regmap)
{ {
struct clk_utmi *utmi = (struct clk_utmi *)dev_id; unsigned int status;
wake_up(&utmi->wait); regmap_read(regmap, AT91_PMC_SR, &status);
disable_irq_nosync(utmi->irq);
return IRQ_HANDLED; return status & AT91_PMC_LOCKU;
} }
static int clk_utmi_prepare(struct clk_hw *hw) static int clk_utmi_prepare(struct clk_hw *hw)
{ {
struct clk_utmi *utmi = to_clk_utmi(hw); struct clk_utmi *utmi = to_clk_utmi(hw);
struct at91_pmc *pmc = utmi->pmc; unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT |
u32 tmp = pmc_read(pmc, AT91_CKGR_UCKR) | AT91_PMC_UPLLEN | AT91_PMC_BIASEN;
AT91_PMC_UPLLCOUNT | AT91_PMC_BIASEN;
pmc_write(pmc, AT91_CKGR_UCKR, tmp); regmap_update_bits(utmi->regmap, AT91_CKGR_UCKR, uckr, uckr);
while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU)) { while (!clk_utmi_ready(utmi->regmap))
enable_irq(utmi->irq); cpu_relax();
wait_event(utmi->wait,
pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU);
}
return 0; return 0;
} }
...@@ -64,18 +52,15 @@ static int clk_utmi_prepare(struct clk_hw *hw) ...@@ -64,18 +52,15 @@ static int clk_utmi_prepare(struct clk_hw *hw)
static int clk_utmi_is_prepared(struct clk_hw *hw) static int clk_utmi_is_prepared(struct clk_hw *hw)
{ {
struct clk_utmi *utmi = to_clk_utmi(hw); struct clk_utmi *utmi = to_clk_utmi(hw);
struct at91_pmc *pmc = utmi->pmc;
return !!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU); return clk_utmi_ready(utmi->regmap);
} }
static void clk_utmi_unprepare(struct clk_hw *hw) static void clk_utmi_unprepare(struct clk_hw *hw)
{ {
struct clk_utmi *utmi = to_clk_utmi(hw); struct clk_utmi *utmi = to_clk_utmi(hw);
struct at91_pmc *pmc = utmi->pmc;
u32 tmp = pmc_read(pmc, AT91_CKGR_UCKR) & ~AT91_PMC_UPLLEN;
pmc_write(pmc, AT91_CKGR_UCKR, tmp); regmap_update_bits(utmi->regmap, AT91_CKGR_UCKR, AT91_PMC_UPLLEN, 0);
} }
static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw, static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw,
...@@ -93,10 +78,9 @@ static const struct clk_ops utmi_ops = { ...@@ -93,10 +78,9 @@ static const struct clk_ops utmi_ops = {
}; };
static struct clk * __init static struct clk * __init
at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq, at91_clk_register_utmi(struct regmap *regmap,
const char *name, const char *parent_name) const char *name, const char *parent_name)
{ {
int ret;
struct clk_utmi *utmi; struct clk_utmi *utmi;
struct clk *clk = NULL; struct clk *clk = NULL;
struct clk_init_data init; struct clk_init_data init;
...@@ -112,52 +96,36 @@ at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq, ...@@ -112,52 +96,36 @@ at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq,
init.flags = CLK_SET_RATE_GATE; init.flags = CLK_SET_RATE_GATE;
utmi->hw.init = &init; utmi->hw.init = &init;
utmi->pmc = pmc; utmi->regmap = regmap;
utmi->irq = irq;
init_waitqueue_head(&utmi->wait);
irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN);
ret = request_irq(utmi->irq, clk_utmi_irq_handler,
IRQF_TRIGGER_HIGH, "clk-utmi", utmi);
if (ret) {
kfree(utmi);
return ERR_PTR(ret);
}
clk = clk_register(NULL, &utmi->hw); clk = clk_register(NULL, &utmi->hw);
if (IS_ERR(clk)) { if (IS_ERR(clk))
free_irq(utmi->irq, utmi);
kfree(utmi); kfree(utmi);
}
return clk; return clk;
} }
static void __init static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
of_at91_clk_utmi_setup(struct device_node *np, struct at91_pmc *pmc)
{ {
unsigned int irq;
struct clk *clk; struct clk *clk;
const char *parent_name; const char *parent_name;
const char *name = np->name; const char *name = np->name;
struct regmap *regmap;
parent_name = of_clk_get_parent_name(np, 0); parent_name = of_clk_get_parent_name(np, 0);
of_property_read_string(np, "clock-output-names", &name); of_property_read_string(np, "clock-output-names", &name);
irq = irq_of_parse_and_map(np, 0); regmap = syscon_node_to_regmap(of_get_parent(np));
if (!irq) if (IS_ERR(regmap))
return; return;
clk = at91_clk_register_utmi(pmc, irq, name, parent_name); clk = at91_clk_register_utmi(regmap, name, parent_name);
if (IS_ERR(clk)) if (IS_ERR(clk))
return; return;
of_clk_add_provider(np, of_clk_src_simple_get, clk); of_clk_add_provider(np, of_clk_src_simple_get, clk);
return; return;
} }
CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi",
void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np, of_at91sam9x5_clk_utmi_setup);
struct at91_pmc *pmc)
{
of_at91_clk_utmi_setup(np, pmc);
}
This diff is collapsed.
...@@ -14,8 +14,11 @@ ...@@ -14,8 +14,11 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/regmap.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
extern spinlock_t pmc_pcr_lock;
struct clk_range { struct clk_range {
unsigned long min; unsigned long min;
unsigned long max; unsigned long max;
...@@ -23,102 +26,7 @@ struct clk_range { ...@@ -23,102 +26,7 @@ struct clk_range {
#define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,} #define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,}
struct at91_pmc_caps {
u32 available_irqs;
};
struct at91_pmc {
void __iomem *regbase;
int virq;
spinlock_t lock;
const struct at91_pmc_caps *caps;
struct irq_domain *irqdomain;
u32 imr;
};
static inline void pmc_lock(struct at91_pmc *pmc)
{
spin_lock(&pmc->lock);
}
static inline void pmc_unlock(struct at91_pmc *pmc)
{
spin_unlock(&pmc->lock);
}
static inline u32 pmc_read(struct at91_pmc *pmc, int offset)
{
return readl(pmc->regbase + offset);
}
static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value)
{
writel(value, pmc->regbase + offset);
}
int of_at91_get_clk_range(struct device_node *np, const char *propname, int of_at91_get_clk_range(struct device_node *np, const char *propname,
struct clk_range *range); struct clk_range *range);
void of_at91sam9260_clk_slow_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91rm9200_clk_main_osc_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91rm9200_clk_main_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91sam9x5_clk_main_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91rm9200_clk_pll_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91sam9g45_clk_pll_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91sam9g20_clk_pllb_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_sama5d3_clk_pll_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91rm9200_clk_master_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91sam9x5_clk_master_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91rm9200_clk_sys_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91rm9200_clk_periph_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91sam9x5_clk_periph_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91rm9200_clk_prog_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91sam9g45_clk_prog_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91sam9x5_clk_prog_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91sam9x5_clk_utmi_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91rm9200_clk_usb_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91sam9x5_clk_usb_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91sam9n12_clk_usb_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_at91sam9x5_clk_smd_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_sama5d4_clk_h32mx_setup(struct device_node *np,
struct at91_pmc *pmc);
void of_sama5d2_clk_generated_setup(struct device_node *np,
struct at91_pmc *pmc);
#endif /* __PMC_H_ */ #endif /* __PMC_H_ */
...@@ -17,7 +17,9 @@ ...@@ -17,7 +17,9 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <linux/usb/atmel_usba_udc.h> #include <linux/usb/atmel_usba_udc.h>
...@@ -1888,20 +1890,15 @@ static int atmel_usba_stop(struct usb_gadget *gadget) ...@@ -1888,20 +1890,15 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
#ifdef CONFIG_OF #ifdef CONFIG_OF
static void at91sam9rl_toggle_bias(struct usba_udc *udc, int is_on) static void at91sam9rl_toggle_bias(struct usba_udc *udc, int is_on)
{ {
unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR); regmap_update_bits(udc->pmc, AT91_CKGR_UCKR, AT91_PMC_BIASEN,
is_on ? AT91_PMC_BIASEN : 0);
if (is_on)
at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
else
at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
} }
static void at91sam9g45_pulse_bias(struct usba_udc *udc) static void at91sam9g45_pulse_bias(struct usba_udc *udc)
{ {
unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR); regmap_update_bits(udc->pmc, AT91_CKGR_UCKR, AT91_PMC_BIASEN, 0);
regmap_update_bits(udc->pmc, AT91_CKGR_UCKR, AT91_PMC_BIASEN,
at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN)); AT91_PMC_BIASEN);
at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
} }
static const struct usba_udc_errata at91sam9rl_errata = { static const struct usba_udc_errata at91sam9rl_errata = {
...@@ -1938,6 +1935,9 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, ...@@ -1938,6 +1935,9 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
udc->errata = match->data; udc->errata = match->data;
udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9g45-pmc");
if (udc->errata && IS_ERR(udc->pmc))
return ERR_CAST(udc->pmc);
udc->num_ep = 0; udc->num_ep = 0;
......
...@@ -354,6 +354,8 @@ struct usba_udc { ...@@ -354,6 +354,8 @@ struct usba_udc {
struct dentry *debugfs_root; struct dentry *debugfs_root;
struct dentry *debugfs_regs; struct dentry *debugfs_regs;
#endif #endif
struct regmap *pmc;
}; };
static inline struct usba_ep *to_usba_ep(struct usb_ep *ep) static inline struct usba_ep *to_usba_ep(struct usb_ep *ep)
......
...@@ -16,18 +16,6 @@ ...@@ -16,18 +16,6 @@
#ifndef AT91_PMC_H #ifndef AT91_PMC_H
#define AT91_PMC_H #define AT91_PMC_H
#ifndef __ASSEMBLY__
extern void __iomem *at91_pmc_base;
#define at91_pmc_read(field) \
readl_relaxed(at91_pmc_base + field)
#define at91_pmc_write(field, value) \
writel_relaxed(value, at91_pmc_base + field)
#else
.extern at91_pmc_base
#endif
#define AT91_PMC_SCER 0x00 /* System Clock Enable Register */ #define AT91_PMC_SCER 0x00 /* System Clock Enable Register */
#define AT91_PMC_SCDR 0x04 /* System Clock Disable Register */ #define AT91_PMC_SCDR 0x04 /* System Clock Disable Register */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment