ARM: SoC driver updates for v4.6
Driver updates for ARM SoCs, these contain various things that touch the drivers/ directory but got merged through arm-soc for practical reasons: - Rockchip rk3368 gains power domain support - Small updates for the ARM spmi driver - The Atmel PMC driver saw a larger rework, touching both arch/arm/mach-at91 and drivers/clk/at91 - All reset controller driver changes alway get merged through arm-soc, though this time the largest change is the addition of a MIPS pistachio reset driver - One bugfix for the NXP (formerly Freescale) i.MX weim bus driver -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIVAwUAVu67OmCrR//JCVInAQJ64hAAqNemdAMloJhh8mk4O74egd/XNE8GLK3v gGefpZNi0TC8u/GWMhU1aFCElaCmbNlL0IlqaRrU/vydOmQcZYht7Fg3bAm4r3ck TlKijGTJap4sdHhxSeui+7bhaBToxcklQTdcrKFgOwsype7CAWJCl5otIC/GHO5L fn4QSjQbqr5kqH1XfuVIphj/fJjDKRRze5D7zn0nExq46OyoYyjc2lm/QkLgeeS2 vDpzOULYXcjf5GfsPknCJGGjenISD7cIAwZukGvJXFh8WrXkEPZZ7B7bBI/8ZeBU MkdWvOm9fHEWpIPnuTcLeQNlfdzQ0Z0zijgJqnXjwSYXK2Es1UKEoIFvZUyGA9zG uyLtddFcKbP4QBDUKVMbyYM6x4Cj7LO96dB2pe8iH5rvnoLS32EjJ/4glnbPQFB7 75JKb7eU1pijoy9c3x/G10vINHzbPjyUN3sYTFKMomPFzEF4OVQ3GDclSuD7jjDr GnqmAqlj29+qGU6iQBBHp9TfLTxwrs/4MKPEZ+tTGvtINnzOpLGA3TUnji7nVFQc BYy3qaEvg9MfHI3uXhAl2L4CGCVvHfqFs5B7giZfAkbbcTNAHs9PkZ6gMYH+GG3p tEbTf/dMHmkkqttSz4f7LZS7D56cSfm3cD8kFCRJPLKifmGAk3w1HZ7JoCXdjr1K 22HSKRMxlhU= =HS4G -----END PGP SIGNATURE----- Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc Pull ARM SoC driver updates from Arnd Bergmann: "Driver updates for ARM SoCs, these contain various things that touch the drivers/ directory but got merged through arm-soc for practical reasons: - Rockchip rk3368 gains power domain support - Small updates for the ARM spmi driver - The Atmel PMC driver saw a larger rework, touching both arch/arm/mach-at91 and drivers/clk/at91 - All reset controller driver changes alway get merged through arm-soc, though this time the largest change is the addition of a MIPS pistachio reset driver - One bugfix for the NXP (formerly Freescale) i.MX weim bus driver" * tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (43 commits) bus: imx-weim: Take the 'status' property value into account 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 hwmon: (scpi) add energy meter support firmware: arm_scpi: add support for 64-bit sensor values firmware: arm_scpi: decrease Tx timeout to 20ms firmware: arm_scpi: fix send_message and sensor_get_value for big-endian reset: sti: Make reset_control_ops const reset: zynq: Make reset_control_ops const ...
This commit is contained in:
commit
46e595a17d
|
@ -46,6 +46,9 @@ Timing properties for child nodes. All are optional and default to 0.
|
|||
- gpmc,adv-on-ns: Assertion time
|
||||
- gpmc,adv-rd-off-ns: Read deassertion time
|
||||
- gpmc,adv-wr-off-ns: Write deassertion time
|
||||
- gpmc,adv-aad-mux-on-ns: Assertion time for AAD
|
||||
- gpmc,adv-aad-mux-rd-off-ns: Read deassertion time for AAD
|
||||
- gpmc,adv-aad-mux-wr-off-ns: Write deassertion time for AAD
|
||||
|
||||
WE signals timings (in nanoseconds) corresponding to GPMC_CONFIG4:
|
||||
- gpmc,we-on-ns Assertion time
|
||||
|
@ -54,6 +57,8 @@ Timing properties for child nodes. All are optional and default to 0.
|
|||
OE signals timings (in nanoseconds) corresponding to GPMC_CONFIG4:
|
||||
- gpmc,oe-on-ns: Assertion time
|
||||
- gpmc,oe-off-ns: Deassertion time
|
||||
- gpmc,oe-aad-mux-on-ns: Assertion time for AAD
|
||||
- gpmc,oe-aad-mux-off-ns: Deassertion time for AAD
|
||||
|
||||
Access time and cycle time timings (in nanoseconds) corresponding to
|
||||
GPMC_CONFIG5:
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
Pistachio Reset Controller
|
||||
=============================================================================
|
||||
|
||||
This binding describes a reset controller device that is used to enable and
|
||||
disable individual IP blocks within the Pistachio SoC using "soft reset"
|
||||
control bits found in the Pistachio SoC top level registers.
|
||||
|
||||
The actual action taken when soft reset is asserted is hardware dependent.
|
||||
However, when asserted it may not be possible to access the hardware's
|
||||
registers, and following an assert/deassert sequence the hardware's previous
|
||||
state may no longer be valid.
|
||||
|
||||
Please refer to Documentation/devicetree/bindings/reset/reset.txt
|
||||
for common reset controller binding usage.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Contains "img,pistachio-reset"
|
||||
|
||||
- #reset-cells: Contains 1
|
||||
|
||||
Example:
|
||||
|
||||
cr_periph: clk@18148000 {
|
||||
compatible = "img,pistachio-cr-periph", "syscon", "simple-mfd";
|
||||
reg = <0x18148000 0x1000>;
|
||||
clocks = <&clk_periph PERIPH_CLK_SYS>;
|
||||
clock-names = "sys";
|
||||
#clock-cells = <1>;
|
||||
|
||||
pistachio_reset: reset-controller {
|
||||
compatible = "img,pistachio-reset";
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
Specifying reset control of devices
|
||||
=======================================
|
||||
|
||||
Device nodes should specify the reset channel required in their "resets"
|
||||
property, containing a phandle to the pistachio reset device node and an
|
||||
index specifying which reset to use, as described in
|
||||
Documentation/devicetree/bindings/reset/reset.txt.
|
||||
|
||||
Example:
|
||||
|
||||
spdif_out: spdif-out@18100d00 {
|
||||
...
|
||||
resets = <&pistachio_reset PISTACHIO_RESET_SPDIF_OUT>;
|
||||
reset-names = "rst";
|
||||
...
|
||||
};
|
||||
|
||||
Macro definitions for the supported resets can be found in:
|
||||
include/dt-bindings/reset/pistachio-resets.h
|
|
@ -6,6 +6,7 @@ powered up/down by software based on different application scenes to save power.
|
|||
Required properties for power domain controller:
|
||||
- compatible: Should be one of the following.
|
||||
"rockchip,rk3288-power-controller" - for RK3288 SoCs.
|
||||
"rockchip,rk3368-power-controller" - for RK3368 SoCs.
|
||||
- #power-domain-cells: Number of cells in a power-domain specifier.
|
||||
Should be 1 for multiple PM domains.
|
||||
- #address-cells: Should be 1.
|
||||
|
@ -14,6 +15,7 @@ Required properties for power domain controller:
|
|||
Required properties for power domain sub nodes:
|
||||
- reg: index of the power domain, should use macros in:
|
||||
"include/dt-bindings/power/rk3288-power.h" - for RK3288 type power domain.
|
||||
"include/dt-bindings/power/rk3368-power.h" - for RK3368 type power domain.
|
||||
- clocks (optional): phandles to clocks which need to be enabled while power domain
|
||||
switches state.
|
||||
|
||||
|
@ -31,11 +33,24 @@ Example:
|
|||
};
|
||||
};
|
||||
|
||||
power: power-controller {
|
||||
compatible = "rockchip,rk3368-power-controller";
|
||||
#power-domain-cells = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pd_gpu_1 {
|
||||
reg = <RK3368_PD_GPU_1>;
|
||||
clocks = <&cru ACLK_GPU_CFG>;
|
||||
};
|
||||
};
|
||||
|
||||
Node of a device using power domains must have a power-domains property,
|
||||
containing a phandle to the power device node and an index specifying which
|
||||
power domain to use.
|
||||
The index should use macros in:
|
||||
"include/dt-bindings/power/rk3288-power.h" - for rk3288 type power domain.
|
||||
"include/dt-bindings/power/rk3368-power.h" - for rk3368 type power domain.
|
||||
|
||||
Example of the node using power domain:
|
||||
|
||||
|
@ -44,3 +59,9 @@ Example of the node using power domain:
|
|||
power-domains = <&power RK3288_PD_GPU>;
|
||||
/* ... */
|
||||
};
|
||||
|
||||
node {
|
||||
/* ... */
|
||||
power-domains = <&power RK3368_PD_GPU_1>;
|
||||
/* ... */
|
||||
};
|
||||
|
|
|
@ -104,6 +104,7 @@ config HAVE_AT91_USB_CLK
|
|||
config COMMON_CLK_AT91
|
||||
bool
|
||||
select COMMON_CLK
|
||||
select MFD_SYSCON
|
||||
|
||||
config HAVE_AT91_SMD
|
||||
bool
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <linux/of_platform.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/system_misc.h>
|
||||
|
||||
#include "generic.h"
|
||||
#include "soc.h"
|
||||
|
@ -33,7 +32,6 @@ static void __init at91rm9200_dt_device_init(void)
|
|||
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, soc_dev);
|
||||
|
||||
arm_pm_idle = at91rm9200_idle;
|
||||
at91rm9200_pm_init();
|
||||
}
|
||||
|
||||
|
|
|
@ -62,8 +62,6 @@ static void __init at91sam9_common_init(void)
|
|||
soc_dev = soc_device_to_device(soc);
|
||||
|
||||
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)
|
||||
|
|
|
@ -11,27 +11,18 @@
|
|||
#ifndef _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
|
||||
extern void __init at91rm9200_pm_init(void);
|
||||
extern void __init at91sam9260_pm_init(void);
|
||||
extern void __init at91sam9g45_pm_init(void);
|
||||
extern void __init at91sam9x5_pm_init(void);
|
||||
extern void __init sama5_pm_init(void);
|
||||
#else
|
||||
static inline void __init at91rm9200_pm_init(void) { }
|
||||
static inline void __init at91sam9260_pm_init(void) { }
|
||||
static inline void __init at91sam9g45_pm_init(void) { }
|
||||
static inline void __init at91sam9x5_pm_init(void) { }
|
||||
static inline void __init sama5_pm_init(void) { }
|
||||
#endif
|
||||
|
||||
#endif /* _AT91_GENERIC_H */
|
||||
|
|
|
@ -31,10 +31,13 @@
|
|||
#include <asm/mach/irq.h>
|
||||
#include <asm/fncpy.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/system_misc.h>
|
||||
|
||||
#include "generic.h"
|
||||
#include "pm.h"
|
||||
|
||||
static void __iomem *pmc;
|
||||
|
||||
/*
|
||||
* FIXME: this is needed to communicate between the pinctrl driver and
|
||||
* the PM implementation in the machine. Possibly part of the PM
|
||||
|
@ -87,7 +90,7 @@ static int at91_pm_verify_clocks(void)
|
|||
unsigned long scsr;
|
||||
int i;
|
||||
|
||||
scsr = at91_pmc_read(AT91_PMC_SCSR);
|
||||
scsr = readl(pmc + AT91_PMC_SCSR);
|
||||
|
||||
/* USB must not be using PLLB */
|
||||
if ((scsr & at91_pm_data.uhp_udp_mask) != 0) {
|
||||
|
@ -101,8 +104,7 @@ static int at91_pm_verify_clocks(void)
|
|||
|
||||
if ((scsr & (AT91_PMC_PCK0 << i)) == 0)
|
||||
continue;
|
||||
|
||||
css = at91_pmc_read(AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
|
||||
css = readl(pmc + AT91_PMC_PCKR(i)) & AT91_PMC_CSS;
|
||||
if (css != AT91_PMC_CSS_SLOW) {
|
||||
pr_err("AT91: PM - Suspend-to-RAM with PCK%d src %d\n", i, css);
|
||||
return 0;
|
||||
|
@ -145,8 +147,8 @@ static void at91_pm_suspend(suspend_state_t state)
|
|||
flush_cache_all();
|
||||
outer_disable();
|
||||
|
||||
at91_suspend_sram_fn(at91_pmc_base, at91_ramc_base[0],
|
||||
at91_ramc_base[1], pm_data);
|
||||
at91_suspend_sram_fn(pmc, at91_ramc_base[0],
|
||||
at91_ramc_base[1], pm_data);
|
||||
|
||||
outer_resume();
|
||||
}
|
||||
|
@ -353,6 +355,21 @@ static __init void at91_dt_ramc(void)
|
|||
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)
|
||||
{
|
||||
struct gen_pool *sram_pool;
|
||||
|
@ -399,13 +416,36 @@ static void __init at91_pm_sram_init(void)
|
|||
&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)
|
||||
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)
|
||||
suspend_set_ops(&at91_pm_ops);
|
||||
else
|
||||
|
@ -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.memctrl = AT91_MEMCTRL_MC;
|
||||
|
||||
at91_pm_init();
|
||||
at91_pm_init(at91rm9200_idle);
|
||||
}
|
||||
|
||||
void __init at91sam9260_pm_init(void)
|
||||
|
@ -432,7 +472,7 @@ void __init at91sam9260_pm_init(void)
|
|||
at91_dt_ramc();
|
||||
at91_pm_data.memctrl = AT91_MEMCTRL_SDRAMC;
|
||||
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)
|
||||
|
@ -440,7 +480,7 @@ void __init at91sam9g45_pm_init(void)
|
|||
at91_dt_ramc();
|
||||
at91_pm_data.uhp_udp_mask = AT91SAM926x_PMC_UHP;
|
||||
at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR;
|
||||
return at91_pm_init();
|
||||
at91_pm_init(at91sam9_idle);
|
||||
}
|
||||
|
||||
void __init at91sam9x5_pm_init(void)
|
||||
|
@ -448,5 +488,13 @@ void __init at91sam9x5_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;
|
||||
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)
|
|||
soc_dev = soc_device_to_device(soc);
|
||||
|
||||
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 = {
|
||||
|
|
|
@ -150,7 +150,7 @@ static int __init weim_parse_dt(struct platform_device *pdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
for_each_child_of_node(pdev->dev.of_node, child) {
|
||||
for_each_available_child_of_node(pdev->dev.of_node, child) {
|
||||
if (!child->name)
|
||||
continue;
|
||||
|
||||
|
|
|
@ -330,7 +330,7 @@ static int sunxi_rsb_read(struct sunxi_rsb *rsb, u8 rtaddr, u8 addr,
|
|||
cmd = RSB_CMD_RD32;
|
||||
break;
|
||||
default:
|
||||
dev_err(rsb->dev, "Invalid access width: %d\n", len);
|
||||
dev_err(rsb->dev, "Invalid access width: %zd\n", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -372,7 +372,7 @@ static int sunxi_rsb_write(struct sunxi_rsb *rsb, u8 rtaddr, u8 addr,
|
|||
cmd = RSB_CMD_WR32;
|
||||
break;
|
||||
default:
|
||||
dev_err(rsb->dev, "Invalid access width: %d\n", len);
|
||||
dev_err(rsb->dev, "Invalid access width: %zd\n", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
|
@ -28,8 +28,9 @@
|
|||
|
||||
struct clk_generated {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
struct regmap *regmap;
|
||||
struct clk_range range;
|
||||
spinlock_t *lock;
|
||||
u32 id;
|
||||
u32 gckdiv;
|
||||
u8 parent_id;
|
||||
|
@ -41,49 +42,52 @@ struct clk_generated {
|
|||
static int clk_generated_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_generated *gck = to_clk_generated(hw);
|
||||
struct at91_pmc *pmc = gck->pmc;
|
||||
u32 tmp;
|
||||
unsigned long flags;
|
||||
|
||||
pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n",
|
||||
__func__, gck->gckdiv, gck->parent_id);
|
||||
|
||||
pmc_lock(pmc);
|
||||
pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK));
|
||||
tmp = pmc_read(pmc, AT91_PMC_PCR) &
|
||||
~(AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK);
|
||||
pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_GCKCSS(gck->parent_id)
|
||||
| AT91_PMC_PCR_CMD
|
||||
| AT91_PMC_PCR_GCKDIV(gck->gckdiv)
|
||||
| AT91_PMC_PCR_GCKEN);
|
||||
pmc_unlock(pmc);
|
||||
spin_lock_irqsave(gck->lock, flags);
|
||||
regmap_write(gck->regmap, AT91_PMC_PCR,
|
||||
(gck->id & AT91_PMC_PCR_PID_MASK));
|
||||
regmap_update_bits(gck->regmap, AT91_PMC_PCR,
|
||||
AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK |
|
||||
AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
|
||||
AT91_PMC_PCR_GCKCSS(gck->parent_id) |
|
||||
AT91_PMC_PCR_CMD |
|
||||
AT91_PMC_PCR_GCKDIV(gck->gckdiv) |
|
||||
AT91_PMC_PCR_GCKEN);
|
||||
spin_unlock_irqrestore(gck->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_generated_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_generated *gck = to_clk_generated(hw);
|
||||
struct at91_pmc *pmc = gck->pmc;
|
||||
u32 tmp;
|
||||
unsigned long flags;
|
||||
|
||||
pmc_lock(pmc);
|
||||
pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK));
|
||||
tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_GCKEN;
|
||||
pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_CMD);
|
||||
pmc_unlock(pmc);
|
||||
spin_lock_irqsave(gck->lock, flags);
|
||||
regmap_write(gck->regmap, AT91_PMC_PCR,
|
||||
(gck->id & AT91_PMC_PCR_PID_MASK));
|
||||
regmap_update_bits(gck->regmap, AT91_PMC_PCR,
|
||||
AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
|
||||
AT91_PMC_PCR_CMD);
|
||||
spin_unlock_irqrestore(gck->lock, flags);
|
||||
}
|
||||
|
||||
static int clk_generated_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_generated *gck = to_clk_generated(hw);
|
||||
struct at91_pmc *pmc = gck->pmc;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
unsigned int status;
|
||||
|
||||
pmc_lock(pmc);
|
||||
pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK));
|
||||
ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_GCKEN);
|
||||
pmc_unlock(pmc);
|
||||
spin_lock_irqsave(gck->lock, flags);
|
||||
regmap_write(gck->regmap, AT91_PMC_PCR,
|
||||
(gck->id & AT91_PMC_PCR_PID_MASK));
|
||||
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
|
||||
|
@ -214,13 +218,14 @@ static const struct clk_ops generated_ops = {
|
|||
*/
|
||||
static void clk_generated_startup(struct clk_generated *gck)
|
||||
{
|
||||
struct at91_pmc *pmc = gck->pmc;
|
||||
u32 tmp;
|
||||
unsigned long flags;
|
||||
|
||||
pmc_lock(pmc);
|
||||
pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK));
|
||||
tmp = pmc_read(pmc, AT91_PMC_PCR);
|
||||
pmc_unlock(pmc);
|
||||
spin_lock_irqsave(gck->lock, flags);
|
||||
regmap_write(gck->regmap, AT91_PMC_PCR,
|
||||
(gck->id & AT91_PMC_PCR_PID_MASK));
|
||||
regmap_read(gck->regmap, AT91_PMC_PCR, &tmp);
|
||||
spin_unlock_irqrestore(gck->lock, flags);
|
||||
|
||||
gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK)
|
||||
>> AT91_PMC_PCR_GCKCSS_OFFSET;
|
||||
|
@ -229,8 +234,8 @@ static void clk_generated_startup(struct clk_generated *gck)
|
|||
}
|
||||
|
||||
static struct clk * __init
|
||||
at91_clk_register_generated(struct at91_pmc *pmc, const char *name,
|
||||
const char **parent_names, u8 num_parents,
|
||||
at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, const char
|
||||
*name, const char **parent_names, u8 num_parents,
|
||||
u8 id, const struct clk_range *range)
|
||||
{
|
||||
struct clk_generated *gck;
|
||||
|
@ -249,7 +254,8 @@ at91_clk_register_generated(struct at91_pmc *pmc, const char *name,
|
|||
|
||||
gck->id = id;
|
||||
gck->hw.init = &init;
|
||||
gck->pmc = pmc;
|
||||
gck->regmap = regmap;
|
||||
gck->lock = lock;
|
||||
gck->range = *range;
|
||||
|
||||
clk = clk_register(NULL, &gck->hw);
|
||||
|
@ -261,8 +267,7 @@ at91_clk_register_generated(struct at91_pmc *pmc, const char *name,
|
|||
return clk;
|
||||
}
|
||||
|
||||
void __init of_sama5d2_clk_generated_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
void __init of_sama5d2_clk_generated_setup(struct device_node *np)
|
||||
{
|
||||
int num;
|
||||
u32 id;
|
||||
|
@ -272,6 +277,7 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np,
|
|||
const char *parent_names[GENERATED_SOURCE_MAX];
|
||||
struct device_node *gcknp;
|
||||
struct clk_range range = CLK_RANGE(0, 0);
|
||||
struct regmap *regmap;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
if (num_parents <= 0 || num_parents > GENERATED_SOURCE_MAX)
|
||||
|
@ -283,6 +289,10 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np,
|
|||
if (!num || num > PERIPHERAL_MAX)
|
||||
return;
|
||||
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
for_each_child_of_node(np, gcknp) {
|
||||
if (of_property_read_u32(gcknp, "reg", &id))
|
||||
continue;
|
||||
|
@ -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",
|
||||
&range);
|
||||
|
||||
clk = at91_clk_register_generated(pmc, name, parent_names,
|
||||
num_parents, id, &range);
|
||||
clk = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
|
||||
parent_names, num_parents,
|
||||
id, &range);
|
||||
if (IS_ERR(clk))
|
||||
continue;
|
||||
|
||||
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 @@
|
|||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
|
@ -31,7 +25,7 @@
|
|||
|
||||
struct clk_sama5d4_h32mx {
|
||||
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)
|
||||
|
@ -40,8 +34,10 @@ static unsigned long clk_sama5d4_h32mx_recalc_rate(struct clk_hw *hw,
|
|||
unsigned long parent_rate)
|
||||
{
|
||||
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;
|
||||
|
||||
if (parent_rate > H32MX_MAX_FREQ)
|
||||
|
@ -70,18 +66,16 @@ static int clk_sama5d4_h32mx_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw);
|
||||
struct at91_pmc *pmc = h32mxclk->pmc;
|
||||
u32 tmp;
|
||||
u32 mckr = 0;
|
||||
|
||||
if (parent_rate != rate && (parent_rate / 2) != rate)
|
||||
return -EINVAL;
|
||||
|
||||
pmc_lock(pmc);
|
||||
tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_H32MXDIV;
|
||||
if ((parent_rate / 2) == rate)
|
||||
tmp |= AT91_PMC_H32MXDIV;
|
||||
pmc_write(pmc, AT91_PMC_MCKR, tmp);
|
||||
pmc_unlock(pmc);
|
||||
mckr = AT91_PMC_H32MXDIV;
|
||||
|
||||
regmap_update_bits(h32mxclk->regmap, AT91_PMC_MCKR,
|
||||
AT91_PMC_H32MXDIV, mckr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -92,14 +86,18 @@ static const struct clk_ops h32mx_ops = {
|
|||
.set_rate = clk_sama5d4_h32mx_set_rate,
|
||||
};
|
||||
|
||||
void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np)
|
||||
{
|
||||
struct clk_sama5d4_h32mx *h32mxclk;
|
||||
struct clk_init_data init;
|
||||
const char *parent_name;
|
||||
struct regmap *regmap;
|
||||
struct clk *clk;
|
||||
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
h32mxclk = kzalloc(sizeof(*h32mxclk), GFP_KERNEL);
|
||||
if (!h32mxclk)
|
||||
return;
|
||||
|
@ -113,7 +111,7 @@ void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
|
|||
init.flags = CLK_SET_RATE_GATE;
|
||||
|
||||
h32mxclk->hw.init = &init;
|
||||
h32mxclk->pmc = pmc;
|
||||
h32mxclk->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &h32mxclk->hw);
|
||||
if (!clk) {
|
||||
|
@ -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);
|
||||
}
|
||||
CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx",
|
||||
of_sama5d4_clk_h32mx_setup);
|
||||
|
|
|
@ -13,13 +13,8 @@
|
|||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
|
@ -34,18 +29,14 @@
|
|||
|
||||
struct clk_main_osc {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
unsigned int irq;
|
||||
wait_queue_head_t wait;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
#define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw)
|
||||
|
||||
struct clk_main_rc_osc {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
unsigned int irq;
|
||||
wait_queue_head_t wait;
|
||||
struct regmap *regmap;
|
||||
unsigned long frequency;
|
||||
unsigned long accuracy;
|
||||
};
|
||||
|
@ -54,51 +45,47 @@ struct clk_main_rc_osc {
|
|||
|
||||
struct clk_rm9200_main {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
#define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw)
|
||||
|
||||
struct clk_sam9x5_main {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
unsigned int irq;
|
||||
wait_queue_head_t wait;
|
||||
struct regmap *regmap;
|
||||
u8 parent;
|
||||
};
|
||||
|
||||
#define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw)
|
||||
|
||||
static irqreturn_t clk_main_osc_irq_handler(int irq, void *dev_id)
|
||||
static inline bool clk_main_osc_ready(struct regmap *regmap)
|
||||
{
|
||||
struct clk_main_osc *osc = dev_id;
|
||||
unsigned int status;
|
||||
|
||||
wake_up(&osc->wait);
|
||||
disable_irq_nosync(osc->irq);
|
||||
regmap_read(regmap, AT91_PMC_SR, &status);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return status & AT91_PMC_MOSCS;
|
||||
}
|
||||
|
||||
static int clk_main_osc_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_main_osc *osc = to_clk_main_osc(hw);
|
||||
struct at91_pmc *pmc = osc->pmc;
|
||||
struct regmap *regmap = osc->regmap;
|
||||
u32 tmp;
|
||||
|
||||
tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK;
|
||||
regmap_read(regmap, AT91_CKGR_MOR, &tmp);
|
||||
tmp &= ~MOR_KEY_MASK;
|
||||
|
||||
if (tmp & AT91_PMC_OSCBYPASS)
|
||||
return 0;
|
||||
|
||||
if (!(tmp & AT91_PMC_MOSCEN)) {
|
||||
tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
|
||||
pmc_write(pmc, AT91_CKGR_MOR, tmp);
|
||||
regmap_write(regmap, AT91_CKGR_MOR, tmp);
|
||||
}
|
||||
|
||||
while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) {
|
||||
enable_irq(osc->irq);
|
||||
wait_event(osc->wait,
|
||||
pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS);
|
||||
}
|
||||
while (!clk_main_osc_ready(regmap))
|
||||
cpu_relax();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -106,9 +93,10 @@ static int clk_main_osc_prepare(struct clk_hw *hw)
|
|||
static void clk_main_osc_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_main_osc *osc = to_clk_main_osc(hw);
|
||||
struct at91_pmc *pmc = osc->pmc;
|
||||
u32 tmp = pmc_read(pmc, AT91_CKGR_MOR);
|
||||
struct regmap *regmap = osc->regmap;
|
||||
u32 tmp;
|
||||
|
||||
regmap_read(regmap, AT91_CKGR_MOR, &tmp);
|
||||
if (tmp & AT91_PMC_OSCBYPASS)
|
||||
return;
|
||||
|
||||
|
@ -116,20 +104,22 @@ static void clk_main_osc_unprepare(struct clk_hw *hw)
|
|||
return;
|
||||
|
||||
tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
|
||||
pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
|
||||
regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
|
||||
}
|
||||
|
||||
static int clk_main_osc_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_main_osc *osc = to_clk_main_osc(hw);
|
||||
struct at91_pmc *pmc = osc->pmc;
|
||||
u32 tmp = pmc_read(pmc, AT91_CKGR_MOR);
|
||||
struct regmap *regmap = osc->regmap;
|
||||
u32 tmp, status;
|
||||
|
||||
regmap_read(regmap, AT91_CKGR_MOR, &tmp);
|
||||
if (tmp & AT91_PMC_OSCBYPASS)
|
||||
return 1;
|
||||
|
||||
return !!((pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS) &&
|
||||
(pmc_read(pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCEN));
|
||||
regmap_read(regmap, AT91_PMC_SR, &status);
|
||||
|
||||
return (status & AT91_PMC_MOSCS) && (tmp & AT91_PMC_MOSCEN);
|
||||
}
|
||||
|
||||
static const struct clk_ops main_osc_ops = {
|
||||
|
@ -139,18 +129,16 @@ static const struct clk_ops main_osc_ops = {
|
|||
};
|
||||
|
||||
static struct clk * __init
|
||||
at91_clk_register_main_osc(struct at91_pmc *pmc,
|
||||
unsigned int irq,
|
||||
at91_clk_register_main_osc(struct regmap *regmap,
|
||||
const char *name,
|
||||
const char *parent_name,
|
||||
bool bypass)
|
||||
{
|
||||
int ret;
|
||||
struct clk_main_osc *osc;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
|
||||
if (!pmc || !irq || !name || !parent_name)
|
||||
if (!name || !parent_name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
osc = kzalloc(sizeof(*osc), GFP_KERNEL);
|
||||
|
@ -164,85 +152,70 @@ at91_clk_register_main_osc(struct at91_pmc *pmc,
|
|||
init.flags = CLK_IGNORE_UNUSED;
|
||||
|
||||
osc->hw.init = &init;
|
||||
osc->pmc = pmc;
|
||||
osc->irq = irq;
|
||||
|
||||
init_waitqueue_head(&osc->wait);
|
||||
irq_set_status_flags(osc->irq, IRQ_NOAUTOEN);
|
||||
ret = request_irq(osc->irq, clk_main_osc_irq_handler,
|
||||
IRQF_TRIGGER_HIGH, name, osc);
|
||||
if (ret) {
|
||||
kfree(osc);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
osc->regmap = regmap;
|
||||
|
||||
if (bypass)
|
||||
pmc_write(pmc, AT91_CKGR_MOR,
|
||||
(pmc_read(pmc, AT91_CKGR_MOR) &
|
||||
~(MOR_KEY_MASK | AT91_PMC_MOSCEN)) |
|
||||
AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
|
||||
regmap_update_bits(regmap,
|
||||
AT91_CKGR_MOR, MOR_KEY_MASK |
|
||||
AT91_PMC_MOSCEN,
|
||||
AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
|
||||
|
||||
clk = clk_register(NULL, &osc->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
free_irq(irq, osc);
|
||||
if (IS_ERR(clk))
|
||||
kfree(osc);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
unsigned int irq;
|
||||
const char *name = np->name;
|
||||
const char *parent_name;
|
||||
struct regmap *regmap;
|
||||
bool bypass;
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
bypass = of_property_read_bool(np, "atmel,osc-bypass");
|
||||
parent_name = of_clk_get_parent_name(np, 0);
|
||||
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (!irq)
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91_clk_register_main_osc(pmc, irq, name, parent_name, bypass);
|
||||
clk = at91_clk_register_main_osc(regmap, name, parent_name, bypass);
|
||||
if (IS_ERR(clk))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
}
|
||||
CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc",
|
||||
of_at91rm9200_clk_main_osc_setup);
|
||||
|
||||
static irqreturn_t clk_main_rc_osc_irq_handler(int irq, void *dev_id)
|
||||
static bool clk_main_rc_osc_ready(struct regmap *regmap)
|
||||
{
|
||||
struct clk_main_rc_osc *osc = dev_id;
|
||||
unsigned int status;
|
||||
|
||||
wake_up(&osc->wait);
|
||||
disable_irq_nosync(osc->irq);
|
||||
regmap_read(regmap, AT91_PMC_SR, &status);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return status & AT91_PMC_MOSCRCS;
|
||||
}
|
||||
|
||||
static int clk_main_rc_osc_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
|
||||
struct at91_pmc *pmc = osc->pmc;
|
||||
u32 tmp;
|
||||
struct regmap *regmap = osc->regmap;
|
||||
unsigned int mor;
|
||||
|
||||
tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK;
|
||||
regmap_read(regmap, AT91_CKGR_MOR, &mor);
|
||||
|
||||
if (!(tmp & AT91_PMC_MOSCRCEN)) {
|
||||
tmp |= AT91_PMC_MOSCRCEN | AT91_PMC_KEY;
|
||||
pmc_write(pmc, AT91_CKGR_MOR, tmp);
|
||||
}
|
||||
if (!(mor & AT91_PMC_MOSCRCEN))
|
||||
regmap_update_bits(regmap, AT91_CKGR_MOR,
|
||||
MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
|
||||
AT91_PMC_MOSCRCEN | AT91_PMC_KEY);
|
||||
|
||||
while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS)) {
|
||||
enable_irq(osc->irq);
|
||||
wait_event(osc->wait,
|
||||
pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS);
|
||||
}
|
||||
while (!clk_main_rc_osc_ready(regmap))
|
||||
cpu_relax();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -250,23 +223,28 @@ static int clk_main_rc_osc_prepare(struct clk_hw *hw)
|
|||
static void clk_main_rc_osc_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
|
||||
struct at91_pmc *pmc = osc->pmc;
|
||||
u32 tmp = pmc_read(pmc, AT91_CKGR_MOR);
|
||||
struct regmap *regmap = osc->regmap;
|
||||
unsigned int mor;
|
||||
|
||||
if (!(tmp & AT91_PMC_MOSCRCEN))
|
||||
regmap_read(regmap, AT91_CKGR_MOR, &mor);
|
||||
|
||||
if (!(mor & AT91_PMC_MOSCRCEN))
|
||||
return;
|
||||
|
||||
tmp &= ~(MOR_KEY_MASK | AT91_PMC_MOSCRCEN);
|
||||
pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
|
||||
regmap_update_bits(regmap, AT91_CKGR_MOR,
|
||||
MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY);
|
||||
}
|
||||
|
||||
static int clk_main_rc_osc_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
|
||||
struct at91_pmc *pmc = osc->pmc;
|
||||
struct regmap *regmap = osc->regmap;
|
||||
unsigned int mor, status;
|
||||
|
||||
return !!((pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS) &&
|
||||
(pmc_read(pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCRCEN));
|
||||
regmap_read(regmap, AT91_CKGR_MOR, &mor);
|
||||
regmap_read(regmap, AT91_PMC_SR, &status);
|
||||
|
||||
return (mor & AT91_PMC_MOSCRCEN) && (status & AT91_PMC_MOSCRCS);
|
||||
}
|
||||
|
||||
static unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw,
|
||||
|
@ -294,17 +272,15 @@ static const struct clk_ops main_rc_osc_ops = {
|
|||
};
|
||||
|
||||
static struct clk * __init
|
||||
at91_clk_register_main_rc_osc(struct at91_pmc *pmc,
|
||||
unsigned int irq,
|
||||
at91_clk_register_main_rc_osc(struct regmap *regmap,
|
||||
const char *name,
|
||||
u32 frequency, u32 accuracy)
|
||||
{
|
||||
int ret;
|
||||
struct clk_main_rc_osc *osc;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
|
||||
if (!pmc || !irq || !name || !frequency)
|
||||
if (!name || !frequency)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
osc = kzalloc(sizeof(*osc), GFP_KERNEL);
|
||||
|
@ -318,63 +294,53 @@ at91_clk_register_main_rc_osc(struct at91_pmc *pmc,
|
|||
init.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED;
|
||||
|
||||
osc->hw.init = &init;
|
||||
osc->pmc = pmc;
|
||||
osc->irq = irq;
|
||||
osc->regmap = regmap;
|
||||
osc->frequency = frequency;
|
||||
osc->accuracy = accuracy;
|
||||
|
||||
init_waitqueue_head(&osc->wait);
|
||||
irq_set_status_flags(osc->irq, IRQ_NOAUTOEN);
|
||||
ret = request_irq(osc->irq, clk_main_rc_osc_irq_handler,
|
||||
IRQF_TRIGGER_HIGH, name, osc);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
clk = clk_register(NULL, &osc->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
free_irq(irq, osc);
|
||||
if (IS_ERR(clk))
|
||||
kfree(osc);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
unsigned int irq;
|
||||
u32 frequency = 0;
|
||||
u32 accuracy = 0;
|
||||
const char *name = np->name;
|
||||
struct regmap *regmap;
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
of_property_read_u32(np, "clock-frequency", &frequency);
|
||||
of_property_read_u32(np, "clock-accuracy", &accuracy);
|
||||
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (!irq)
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91_clk_register_main_rc_osc(pmc, irq, name, frequency,
|
||||
accuracy);
|
||||
clk = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy);
|
||||
if (IS_ERR(clk))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9x5_clk_main_rc_osc, "atmel,at91sam9x5-clk-main-rc-osc",
|
||||
of_at91sam9x5_clk_main_rc_osc_setup);
|
||||
|
||||
|
||||
static int clk_main_probe_frequency(struct at91_pmc *pmc)
|
||||
static int clk_main_probe_frequency(struct regmap *regmap)
|
||||
{
|
||||
unsigned long prep_time, timeout;
|
||||
u32 tmp;
|
||||
unsigned int mcfr;
|
||||
|
||||
timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT);
|
||||
do {
|
||||
prep_time = jiffies;
|
||||
tmp = pmc_read(pmc, AT91_CKGR_MCFR);
|
||||
if (tmp & AT91_PMC_MAINRDY)
|
||||
regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
|
||||
if (mcfr & AT91_PMC_MAINRDY)
|
||||
return 0;
|
||||
usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);
|
||||
} while (time_before(prep_time, timeout));
|
||||
|
@ -382,34 +348,37 @@ static int clk_main_probe_frequency(struct at91_pmc *pmc)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static unsigned long clk_main_recalc_rate(struct at91_pmc *pmc,
|
||||
static unsigned long clk_main_recalc_rate(struct regmap *regmap,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 tmp;
|
||||
unsigned int mcfr;
|
||||
|
||||
if (parent_rate)
|
||||
return parent_rate;
|
||||
|
||||
pr_warn("Main crystal frequency not set, using approximate value\n");
|
||||
tmp = pmc_read(pmc, AT91_CKGR_MCFR);
|
||||
if (!(tmp & AT91_PMC_MAINRDY))
|
||||
regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
|
||||
if (!(mcfr & AT91_PMC_MAINRDY))
|
||||
return 0;
|
||||
|
||||
return ((tmp & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
|
||||
return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
|
||||
}
|
||||
|
||||
static int clk_rm9200_main_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
|
||||
|
||||
return clk_main_probe_frequency(clkmain->pmc);
|
||||
return clk_main_probe_frequency(clkmain->regmap);
|
||||
}
|
||||
|
||||
static int clk_rm9200_main_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
|
||||
unsigned int status;
|
||||
|
||||
return !!(pmc_read(clkmain->pmc, AT91_CKGR_MCFR) & AT91_PMC_MAINRDY);
|
||||
regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status);
|
||||
|
||||
return status & AT91_PMC_MAINRDY ? 1 : 0;
|
||||
}
|
||||
|
||||
static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
|
||||
|
@ -417,7 +386,7 @@ static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
|
|||
{
|
||||
struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
|
||||
|
||||
return clk_main_recalc_rate(clkmain->pmc, parent_rate);
|
||||
return clk_main_recalc_rate(clkmain->regmap, parent_rate);
|
||||
}
|
||||
|
||||
static const struct clk_ops rm9200_main_ops = {
|
||||
|
@ -427,7 +396,7 @@ static const struct clk_ops rm9200_main_ops = {
|
|||
};
|
||||
|
||||
static struct clk * __init
|
||||
at91_clk_register_rm9200_main(struct at91_pmc *pmc,
|
||||
at91_clk_register_rm9200_main(struct regmap *regmap,
|
||||
const char *name,
|
||||
const char *parent_name)
|
||||
{
|
||||
|
@ -435,7 +404,7 @@ at91_clk_register_rm9200_main(struct at91_pmc *pmc,
|
|||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
|
||||
if (!pmc || !name)
|
||||
if (!name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!parent_name)
|
||||
|
@ -452,7 +421,7 @@ at91_clk_register_rm9200_main(struct at91_pmc *pmc,
|
|||
init.flags = 0;
|
||||
|
||||
clkmain->hw.init = &init;
|
||||
clkmain->pmc = pmc;
|
||||
clkmain->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &clkmain->hw);
|
||||
if (IS_ERR(clk))
|
||||
|
@ -461,52 +430,54 @@ at91_clk_register_rm9200_main(struct at91_pmc *pmc,
|
|||
return clk;
|
||||
}
|
||||
|
||||
void __init of_at91rm9200_clk_main_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91rm9200_clk_main_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
struct regmap *regmap;
|
||||
|
||||
parent_name = of_clk_get_parent_name(np, 0);
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
clk = at91_clk_register_rm9200_main(pmc, name, parent_name);
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91_clk_register_rm9200_main(regmap, name, parent_name);
|
||||
if (IS_ERR(clk))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
}
|
||||
CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main",
|
||||
of_at91rm9200_clk_main_setup);
|
||||
|
||||
static irqreturn_t clk_sam9x5_main_irq_handler(int irq, void *dev_id)
|
||||
static inline bool clk_sam9x5_main_ready(struct regmap *regmap)
|
||||
{
|
||||
struct clk_sam9x5_main *clkmain = dev_id;
|
||||
unsigned int status;
|
||||
|
||||
wake_up(&clkmain->wait);
|
||||
disable_irq_nosync(clkmain->irq);
|
||||
regmap_read(regmap, AT91_PMC_SR, &status);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return status & AT91_PMC_MOSCSELS ? 1 : 0;
|
||||
}
|
||||
|
||||
static int clk_sam9x5_main_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
|
||||
struct at91_pmc *pmc = clkmain->pmc;
|
||||
struct regmap *regmap = clkmain->regmap;
|
||||
|
||||
while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS)) {
|
||||
enable_irq(clkmain->irq);
|
||||
wait_event(clkmain->wait,
|
||||
pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS);
|
||||
}
|
||||
while (!clk_sam9x5_main_ready(regmap))
|
||||
cpu_relax();
|
||||
|
||||
return clk_main_probe_frequency(pmc);
|
||||
return clk_main_probe_frequency(regmap);
|
||||
}
|
||||
|
||||
static int clk_sam9x5_main_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
|
||||
|
||||
return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS);
|
||||
return clk_sam9x5_main_ready(clkmain->regmap);
|
||||
}
|
||||
|
||||
static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw,
|
||||
|
@ -514,30 +485,28 @@ static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw,
|
|||
{
|
||||
struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
|
||||
|
||||
return clk_main_recalc_rate(clkmain->pmc, parent_rate);
|
||||
return clk_main_recalc_rate(clkmain->regmap, parent_rate);
|
||||
}
|
||||
|
||||
static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
|
||||
struct at91_pmc *pmc = clkmain->pmc;
|
||||
u32 tmp;
|
||||
struct regmap *regmap = clkmain->regmap;
|
||||
unsigned int tmp;
|
||||
|
||||
if (index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK;
|
||||
regmap_read(regmap, AT91_CKGR_MOR, &tmp);
|
||||
tmp &= ~MOR_KEY_MASK;
|
||||
|
||||
if (index && !(tmp & AT91_PMC_MOSCSEL))
|
||||
pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL);
|
||||
regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL);
|
||||
else if (!index && (tmp & AT91_PMC_MOSCSEL))
|
||||
pmc_write(pmc, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
|
||||
regmap_write(regmap, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
|
||||
|
||||
while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS)) {
|
||||
enable_irq(clkmain->irq);
|
||||
wait_event(clkmain->wait,
|
||||
pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS);
|
||||
}
|
||||
while (!clk_sam9x5_main_ready(regmap))
|
||||
cpu_relax();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -545,8 +514,11 @@ static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
|
|||
static u8 clk_sam9x5_main_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
|
||||
unsigned int status;
|
||||
|
||||
return !!(pmc_read(clkmain->pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCEN);
|
||||
regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
|
||||
|
||||
return status & AT91_PMC_MOSCEN ? 1 : 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops sam9x5_main_ops = {
|
||||
|
@ -558,18 +530,17 @@ static const struct clk_ops sam9x5_main_ops = {
|
|||
};
|
||||
|
||||
static struct clk * __init
|
||||
at91_clk_register_sam9x5_main(struct at91_pmc *pmc,
|
||||
unsigned int irq,
|
||||
at91_clk_register_sam9x5_main(struct regmap *regmap,
|
||||
const char *name,
|
||||
const char **parent_names,
|
||||
int num_parents)
|
||||
{
|
||||
int ret;
|
||||
struct clk_sam9x5_main *clkmain;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
unsigned int status;
|
||||
|
||||
if (!pmc || !irq || !name)
|
||||
if (!name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!parent_names || !num_parents)
|
||||
|
@ -586,51 +557,42 @@ at91_clk_register_sam9x5_main(struct at91_pmc *pmc,
|
|||
init.flags = CLK_SET_PARENT_GATE;
|
||||
|
||||
clkmain->hw.init = &init;
|
||||
clkmain->pmc = pmc;
|
||||
clkmain->irq = irq;
|
||||
clkmain->parent = !!(pmc_read(clkmain->pmc, AT91_CKGR_MOR) &
|
||||
AT91_PMC_MOSCEN);
|
||||
init_waitqueue_head(&clkmain->wait);
|
||||
irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN);
|
||||
ret = request_irq(clkmain->irq, clk_sam9x5_main_irq_handler,
|
||||
IRQF_TRIGGER_HIGH, name, clkmain);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
clkmain->regmap = regmap;
|
||||
regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
|
||||
clkmain->parent = status & AT91_PMC_MOSCEN ? 1 : 0;
|
||||
|
||||
clk = clk_register(NULL, &clkmain->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
free_irq(clkmain->irq, clkmain);
|
||||
if (IS_ERR(clk))
|
||||
kfree(clkmain);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
void __init of_at91sam9x5_clk_main_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *parent_names[2];
|
||||
int num_parents;
|
||||
unsigned int irq;
|
||||
const char *name = np->name;
|
||||
struct regmap *regmap;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
if (num_parents <= 0 || num_parents > 2)
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (!irq)
|
||||
return;
|
||||
|
||||
clk = at91_clk_register_sam9x5_main(pmc, irq, name, parent_names,
|
||||
clk = at91_clk_register_sam9x5_main(regmap, name, parent_names,
|
||||
num_parents);
|
||||
if (IS_ERR(clk))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main",
|
||||
of_at91sam9x5_clk_main_setup);
|
||||
|
|
|
@ -12,13 +12,8 @@
|
|||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
|
@ -44,32 +39,26 @@ struct clk_master_layout {
|
|||
|
||||
struct clk_master {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
unsigned int irq;
|
||||
wait_queue_head_t wait;
|
||||
struct regmap *regmap;
|
||||
const struct clk_master_layout *layout;
|
||||
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);
|
||||
disable_irq_nosync(master->irq);
|
||||
regmap_read(regmap, AT91_PMC_SR, &status);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return status & AT91_PMC_MCKRDY ? 1 : 0;
|
||||
}
|
||||
|
||||
static int clk_master_prepare(struct clk_hw *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)) {
|
||||
enable_irq(master->irq);
|
||||
wait_event(master->wait,
|
||||
pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MCKRDY);
|
||||
}
|
||||
while (!clk_master_ready(master->regmap))
|
||||
cpu_relax();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -78,7 +67,7 @@ static int clk_master_is_prepared(struct clk_hw *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,
|
||||
|
@ -88,18 +77,16 @@ static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
|
|||
u8 div;
|
||||
unsigned long rate = parent_rate;
|
||||
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_characteristics *characteristics =
|
||||
master->characteristics;
|
||||
u32 tmp;
|
||||
unsigned int mckr;
|
||||
|
||||
pmc_lock(pmc);
|
||||
tmp = pmc_read(pmc, AT91_PMC_MCKR) & layout->mask;
|
||||
pmc_unlock(pmc);
|
||||
regmap_read(master->regmap, AT91_PMC_MCKR, &mckr);
|
||||
mckr &= layout->mask;
|
||||
|
||||
pres = (tmp >> layout->pres_shift) & MASTER_PRES_MASK;
|
||||
div = (tmp >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
|
||||
pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK;
|
||||
div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
|
||||
|
||||
if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX)
|
||||
rate /= 3;
|
||||
|
@ -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)
|
||||
{
|
||||
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 = {
|
||||
|
@ -132,18 +121,17 @@ static const struct clk_ops master_ops = {
|
|||
};
|
||||
|
||||
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 **parent_names,
|
||||
const struct clk_master_layout *layout,
|
||||
const struct clk_master_characteristics *characteristics)
|
||||
{
|
||||
int ret;
|
||||
struct clk_master *master;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
|
||||
if (!pmc || !irq || !name || !num_parents || !parent_names)
|
||||
if (!name || !num_parents || !parent_names)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
master = kzalloc(sizeof(*master), GFP_KERNEL);
|
||||
|
@ -159,20 +147,10 @@ at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq,
|
|||
master->hw.init = &init;
|
||||
master->layout = layout;
|
||||
master->characteristics = characteristics;
|
||||
master->pmc = pmc;
|
||||
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);
|
||||
}
|
||||
master->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &master->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
free_irq(master->irq, master);
|
||||
kfree(master);
|
||||
}
|
||||
|
||||
|
@ -217,15 +195,15 @@ out_free_characteristics:
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct clk *clk;
|
||||
int num_parents;
|
||||
unsigned int irq;
|
||||
const char *parent_names[MASTER_SOURCE_MAX];
|
||||
const char *name = np->name;
|
||||
struct clk_master_characteristics *characteristics;
|
||||
struct regmap *regmap;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
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,
|
|||
if (!characteristics)
|
||||
return;
|
||||
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (!irq)
|
||||
goto out_free_characteristics;
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91_clk_register_master(pmc, irq, name, num_parents,
|
||||
clk = at91_clk_register_master(regmap, name, num_parents,
|
||||
parent_names, layout,
|
||||
characteristics);
|
||||
if (IS_ERR(clk))
|
||||
|
@ -256,14 +234,16 @@ out_free_characteristics:
|
|||
kfree(characteristics);
|
||||
}
|
||||
|
||||
void __init of_at91rm9200_clk_master_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91rm9200_clk_master_setup(struct device_node *np)
|
||||
{
|
||||
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,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9x5_clk_master_setup(struct device_node *np)
|
||||
{
|
||||
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 @@
|
|||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
DEFINE_SPINLOCK(pmc_pcr_lock);
|
||||
|
||||
#define PERIPHERAL_MAX 64
|
||||
|
||||
#define PERIPHERAL_AT91RM9200 0
|
||||
|
@ -33,7 +35,7 @@
|
|||
|
||||
struct clk_peripheral {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
struct regmap *regmap;
|
||||
u32 id;
|
||||
};
|
||||
|
||||
|
@ -41,8 +43,9 @@ struct clk_peripheral {
|
|||
|
||||
struct clk_sam9x5_peripheral {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
struct regmap *regmap;
|
||||
struct clk_range range;
|
||||
spinlock_t *lock;
|
||||
u32 id;
|
||||
u32 div;
|
||||
bool auto_div;
|
||||
|
@ -54,7 +57,6 @@ struct clk_sam9x5_peripheral {
|
|||
static int clk_peripheral_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_peripheral *periph = to_clk_peripheral(hw);
|
||||
struct at91_pmc *pmc = periph->pmc;
|
||||
int offset = AT91_PMC_PCER;
|
||||
u32 id = periph->id;
|
||||
|
||||
|
@ -62,14 +64,14 @@ static int clk_peripheral_enable(struct clk_hw *hw)
|
|||
return 0;
|
||||
if (id > PERIPHERAL_ID_MAX)
|
||||
offset = AT91_PMC_PCER1;
|
||||
pmc_write(pmc, offset, PERIPHERAL_MASK(id));
|
||||
regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_peripheral_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_peripheral *periph = to_clk_peripheral(hw);
|
||||
struct at91_pmc *pmc = periph->pmc;
|
||||
int offset = AT91_PMC_PCDR;
|
||||
u32 id = periph->id;
|
||||
|
||||
|
@ -77,21 +79,23 @@ static void clk_peripheral_disable(struct clk_hw *hw)
|
|||
return;
|
||||
if (id > PERIPHERAL_ID_MAX)
|
||||
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)
|
||||
{
|
||||
struct clk_peripheral *periph = to_clk_peripheral(hw);
|
||||
struct at91_pmc *pmc = periph->pmc;
|
||||
int offset = AT91_PMC_PCSR;
|
||||
unsigned int status;
|
||||
u32 id = periph->id;
|
||||
|
||||
if (id < PERIPHERAL_ID_MIN)
|
||||
return 1;
|
||||
if (id > PERIPHERAL_ID_MAX)
|
||||
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 = {
|
||||
|
@ -101,14 +105,14 @@ static const struct clk_ops peripheral_ops = {
|
|||
};
|
||||
|
||||
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)
|
||||
{
|
||||
struct clk_peripheral *periph;
|
||||
struct clk *clk = NULL;
|
||||
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);
|
||||
|
||||
periph = kzalloc(sizeof(*periph), GFP_KERNEL);
|
||||
|
@ -123,7 +127,7 @@ at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name,
|
|||
|
||||
periph->id = id;
|
||||
periph->hw.init = &init;
|
||||
periph->pmc = pmc;
|
||||
periph->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &periph->hw);
|
||||
if (IS_ERR(clk))
|
||||
|
@ -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)
|
||||
{
|
||||
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
|
||||
struct at91_pmc *pmc = periph->pmc;
|
||||
u32 tmp;
|
||||
unsigned long flags;
|
||||
|
||||
if (periph->id < PERIPHERAL_ID_MIN)
|
||||
return 0;
|
||||
|
||||
pmc_lock(pmc);
|
||||
pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK));
|
||||
tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_DIV_MASK;
|
||||
pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_DIV(periph->div)
|
||||
| AT91_PMC_PCR_CMD
|
||||
| AT91_PMC_PCR_EN);
|
||||
pmc_unlock(pmc);
|
||||
spin_lock_irqsave(periph->lock, flags);
|
||||
regmap_write(periph->regmap, AT91_PMC_PCR,
|
||||
(periph->id & AT91_PMC_PCR_PID_MASK));
|
||||
regmap_update_bits(periph->regmap, AT91_PMC_PCR,
|
||||
AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD |
|
||||
AT91_PMC_PCR_EN,
|
||||
AT91_PMC_PCR_DIV(periph->div) |
|
||||
AT91_PMC_PCR_CMD |
|
||||
AT91_PMC_PCR_EN);
|
||||
spin_unlock_irqrestore(periph->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
|
||||
struct at91_pmc *pmc = periph->pmc;
|
||||
u32 tmp;
|
||||
unsigned long flags;
|
||||
|
||||
if (periph->id < PERIPHERAL_ID_MIN)
|
||||
return;
|
||||
|
||||
pmc_lock(pmc);
|
||||
pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK));
|
||||
tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_EN;
|
||||
pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_CMD);
|
||||
pmc_unlock(pmc);
|
||||
spin_lock_irqsave(periph->lock, flags);
|
||||
regmap_write(periph->regmap, AT91_PMC_PCR,
|
||||
(periph->id & AT91_PMC_PCR_PID_MASK));
|
||||
regmap_update_bits(periph->regmap, AT91_PMC_PCR,
|
||||
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)
|
||||
{
|
||||
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
|
||||
struct at91_pmc *pmc = periph->pmc;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
unsigned int status;
|
||||
|
||||
if (periph->id < PERIPHERAL_ID_MIN)
|
||||
return 1;
|
||||
|
||||
pmc_lock(pmc);
|
||||
pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK));
|
||||
ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_EN);
|
||||
pmc_unlock(pmc);
|
||||
spin_lock_irqsave(periph->lock, flags);
|
||||
regmap_write(periph->regmap, AT91_PMC_PCR,
|
||||
(periph->id & AT91_PMC_PCR_PID_MASK));
|
||||
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
|
||||
|
@ -214,19 +223,20 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
|
|||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
|
||||
struct at91_pmc *pmc = periph->pmc;
|
||||
u32 tmp;
|
||||
unsigned long flags;
|
||||
unsigned int status;
|
||||
|
||||
if (periph->id < PERIPHERAL_ID_MIN)
|
||||
return parent_rate;
|
||||
|
||||
pmc_lock(pmc);
|
||||
pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK));
|
||||
tmp = pmc_read(pmc, AT91_PMC_PCR);
|
||||
pmc_unlock(pmc);
|
||||
spin_lock_irqsave(periph->lock, flags);
|
||||
regmap_write(periph->regmap, AT91_PMC_PCR,
|
||||
(periph->id & AT91_PMC_PCR_PID_MASK));
|
||||
regmap_read(periph->regmap, AT91_PMC_PCR, &status);
|
||||
spin_unlock_irqrestore(periph->lock, flags);
|
||||
|
||||
if (tmp & AT91_PMC_PCR_EN) {
|
||||
periph->div = PERIPHERAL_RSHIFT(tmp);
|
||||
if (status & AT91_PMC_PCR_EN) {
|
||||
periph->div = PERIPHERAL_RSHIFT(status);
|
||||
periph->auto_div = false;
|
||||
} else {
|
||||
clk_sam9x5_peripheral_autodiv(periph);
|
||||
|
@ -318,15 +328,15 @@ static const struct clk_ops sam9x5_peripheral_ops = {
|
|||
};
|
||||
|
||||
static struct clk * __init
|
||||
at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name,
|
||||
const char *parent_name, u32 id,
|
||||
const struct clk_range *range)
|
||||
at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
|
||||
const char *name, const char *parent_name,
|
||||
u32 id, const struct clk_range *range)
|
||||
{
|
||||
struct clk_sam9x5_peripheral *periph;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
|
||||
if (!pmc || !name || !parent_name)
|
||||
if (!name || !parent_name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
periph = kzalloc(sizeof(*periph), GFP_KERNEL);
|
||||
|
@ -342,7 +352,8 @@ at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name,
|
|||
periph->id = id;
|
||||
periph->hw.init = &init;
|
||||
periph->div = 0;
|
||||
periph->pmc = pmc;
|
||||
periph->regmap = regmap;
|
||||
periph->lock = lock;
|
||||
periph->auto_div = true;
|
||||
periph->range = *range;
|
||||
|
||||
|
@ -356,7 +367,7 @@ at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name,
|
|||
}
|
||||
|
||||
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;
|
||||
u32 id;
|
||||
|
@ -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 *name;
|
||||
struct device_node *periphclknp;
|
||||
struct regmap *regmap;
|
||||
|
||||
parent_name = of_clk_get_parent_name(np, 0);
|
||||
if (!parent_name)
|
||||
|
@ -373,6 +385,10 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
|
|||
if (!num || num > PERIPHERAL_MAX)
|
||||
return;
|
||||
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
for_each_child_of_node(np, periphclknp) {
|
||||
if (of_property_read_u32(periphclknp, "reg", &id))
|
||||
continue;
|
||||
|
@ -384,7 +400,7 @@ of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
|
|||
name = periphclknp->name;
|
||||
|
||||
if (type == PERIPHERAL_AT91RM9200) {
|
||||
clk = at91_clk_register_peripheral(pmc, name,
|
||||
clk = at91_clk_register_peripheral(regmap, name,
|
||||
parent_name, id);
|
||||
} else {
|
||||
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)
|
|||
"atmel,clk-output-range",
|
||||
&range);
|
||||
|
||||
clk = at91_clk_register_sam9x5_peripheral(pmc, name,
|
||||
clk = at91_clk_register_sam9x5_peripheral(regmap,
|
||||
&pmc_pcr_lock,
|
||||
name,
|
||||
parent_name,
|
||||
id, &range);
|
||||
}
|
||||
|
@ -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,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91rm9200_clk_periph_setup(struct device_node *np)
|
||||
{
|
||||
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,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np)
|
||||
{
|
||||
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 @@
|
|||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.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 <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
|
@ -58,9 +52,7 @@ struct clk_pll_layout {
|
|||
|
||||
struct clk_pll {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
unsigned int irq;
|
||||
wait_queue_head_t wait;
|
||||
struct regmap *regmap;
|
||||
u8 id;
|
||||
u8 div;
|
||||
u8 range;
|
||||
|
@ -69,20 +61,19 @@ struct clk_pll {
|
|||
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);
|
||||
disable_irq_nosync(pll->irq);
|
||||
regmap_read(regmap, AT91_PMC_SR, &status);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return status & PLL_STATUS_MASK(id) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int clk_pll_prepare(struct clk_hw *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_characteristics *characteristics =
|
||||
pll->characteristics;
|
||||
|
@ -90,39 +81,34 @@ static int clk_pll_prepare(struct clk_hw *hw)
|
|||
u32 mask = PLL_STATUS_MASK(id);
|
||||
int offset = PLL_REG(id);
|
||||
u8 out = 0;
|
||||
u32 pllr, icpr;
|
||||
unsigned int pllr;
|
||||
unsigned int status;
|
||||
u8 div;
|
||||
u16 mul;
|
||||
|
||||
pllr = pmc_read(pmc, offset);
|
||||
regmap_read(regmap, offset, &pllr);
|
||||
div = PLL_DIV(pllr);
|
||||
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))
|
||||
return 0;
|
||||
|
||||
if (characteristics->out)
|
||||
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;
|
||||
pllr |= layout->pllr_mask &
|
||||
(pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) |
|
||||
(out << PLL_OUT_SHIFT) |
|
||||
((pll->mul & layout->mul_mask) << layout->mul_shift));
|
||||
pmc_write(pmc, offset, pllr);
|
||||
if (characteristics->icpll)
|
||||
regmap_update_bits(regmap, AT91_PMC_PLLICPR, PLL_ICPR_MASK(id),
|
||||
characteristics->icpll[pll->range] << PLL_ICPR_SHIFT(id));
|
||||
|
||||
while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) {
|
||||
enable_irq(pll->irq);
|
||||
wait_event(pll->wait,
|
||||
pmc_read(pmc, AT91_PMC_SR) & mask);
|
||||
}
|
||||
regmap_update_bits(regmap, offset, layout->pllr_mask,
|
||||
pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) |
|
||||
(out << PLL_OUT_SHIFT) |
|
||||
((pll->mul & layout->mul_mask) << layout->mul_shift));
|
||||
|
||||
while (!clk_pll_ready(regmap, pll->id))
|
||||
cpu_relax();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -130,32 +116,35 @@ static int clk_pll_prepare(struct clk_hw *hw)
|
|||
static int clk_pll_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pll *pll = to_clk_pll(hw);
|
||||
struct at91_pmc *pmc = pll->pmc;
|
||||
|
||||
return !!(pmc_read(pmc, AT91_PMC_SR) &
|
||||
PLL_STATUS_MASK(pll->id));
|
||||
return clk_pll_ready(pll->regmap, pll->id);
|
||||
}
|
||||
|
||||
static void clk_pll_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pll *pll = to_clk_pll(hw);
|
||||
struct at91_pmc *pmc = pll->pmc;
|
||||
const struct clk_pll_layout *layout = pll->layout;
|
||||
int offset = PLL_REG(pll->id);
|
||||
u32 tmp = pmc_read(pmc, offset) & ~(layout->pllr_mask);
|
||||
unsigned int mask = pll->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,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
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 (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,
|
||||
|
@ -308,7 +297,7 @@ static const struct clk_ops pll_ops = {
|
|||
};
|
||||
|
||||
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 struct clk_pll_layout *layout,
|
||||
const struct clk_pll_characteristics *characteristics)
|
||||
|
@ -316,9 +305,8 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
|
|||
struct clk_pll *pll;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
int offset = PLL_REG(id);
|
||||
u32 tmp;
|
||||
unsigned int pllr;
|
||||
|
||||
if (id > PLL_MAX_ID)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
@ -337,23 +325,13 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
|
|||
pll->hw.init = &init;
|
||||
pll->layout = layout;
|
||||
pll->characteristics = characteristics;
|
||||
pll->pmc = pmc;
|
||||
pll->irq = irq;
|
||||
tmp = pmc_read(pmc, offset) & layout->pllr_mask;
|
||||
pll->div = PLL_DIV(tmp);
|
||||
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);
|
||||
}
|
||||
pll->regmap = regmap;
|
||||
regmap_read(regmap, offset, &pllr);
|
||||
pll->div = PLL_DIV(pllr);
|
||||
pll->mul = PLL_MUL(pllr, layout);
|
||||
|
||||
clk = clk_register(NULL, &pll->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
free_irq(pll->irq, pll);
|
||||
kfree(pll);
|
||||
}
|
||||
|
||||
|
@ -483,12 +461,12 @@ out_free_characteristics:
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
u32 id;
|
||||
unsigned int irq;
|
||||
struct clk *clk;
|
||||
struct regmap *regmap;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
struct clk_pll_characteristics *characteristics;
|
||||
|
@ -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);
|
||||
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
characteristics = of_at91_clk_pll_get_characteristics(np);
|
||||
if (!characteristics)
|
||||
return;
|
||||
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (!irq)
|
||||
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);
|
||||
if (IS_ERR(clk))
|
||||
goto out_free_characteristics;
|
||||
|
@ -520,26 +498,30 @@ out_free_characteristics:
|
|||
kfree(characteristics);
|
||||
}
|
||||
|
||||
void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91rm9200_clk_pll_setup(struct device_node *np)
|
||||
{
|
||||
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,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9g45_clk_pll_setup(struct device_node *np)
|
||||
{
|
||||
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,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np)
|
||||
{
|
||||
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,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_sama5d3_clk_pll_setup(struct device_node *np)
|
||||
{
|
||||
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 @@
|
|||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
|
@ -21,16 +21,18 @@
|
|||
|
||||
struct clk_plldiv {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
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;
|
||||
|
@ -57,18 +59,12 @@ static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
unsigned long parent_rate)
|
||||
{
|
||||
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;
|
||||
|
||||
pmc_lock(pmc);
|
||||
tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_PLLADIV2;
|
||||
if ((parent_rate / 2) == rate)
|
||||
tmp |= AT91_PMC_PLLADIV2;
|
||||
pmc_write(pmc, AT91_PMC_MCKR, tmp);
|
||||
pmc_unlock(pmc);
|
||||
regmap_update_bits(plldiv->regmap, AT91_PMC_MCKR, AT91_PMC_PLLADIV2,
|
||||
parent_rate != rate ? AT91_PMC_PLLADIV2 : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -80,7 +76,7 @@ static const struct clk_ops plldiv_ops = {
|
|||
};
|
||||
|
||||
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)
|
||||
{
|
||||
struct clk_plldiv *plldiv;
|
||||
|
@ -98,7 +94,7 @@ at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name,
|
|||
init.flags = CLK_SET_RATE_GATE;
|
||||
|
||||
plldiv->hw.init = &init;
|
||||
plldiv->pmc = pmc;
|
||||
plldiv->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &plldiv->hw);
|
||||
|
||||
|
@ -109,27 +105,27 @@ at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name,
|
|||
}
|
||||
|
||||
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;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
struct regmap *regmap;
|
||||
|
||||
parent_name = of_clk_get_parent_name(np, 0);
|
||||
|
||||
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))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
return;
|
||||
}
|
||||
|
||||
void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
{
|
||||
of_at91_clk_plldiv_setup(np, pmc);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv",
|
||||
of_at91sam9x5_clk_plldiv_setup);
|
||||
|
|
|
@ -12,10 +12,8 @@
|
|||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
|
@ -24,6 +22,7 @@
|
|||
|
||||
#define PROG_STATUS_MASK(id) (1 << ((id) + 8))
|
||||
#define PROG_PRES_MASK 0x7
|
||||
#define PROG_PRES(layout, pckr) ((pckr >> layout->pres_shift) & PROG_PRES_MASK)
|
||||
#define PROG_MAX_RM9200_CSS 3
|
||||
|
||||
struct clk_programmable_layout {
|
||||
|
@ -34,7 +33,7 @@ struct clk_programmable_layout {
|
|||
|
||||
struct clk_programmable {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
struct regmap *regmap;
|
||||
u8 id;
|
||||
const struct clk_programmable_layout *layout;
|
||||
};
|
||||
|
@ -44,14 +43,12 @@ struct clk_programmable {
|
|||
static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 pres;
|
||||
struct clk_programmable *prog = to_clk_programmable(hw);
|
||||
struct at91_pmc *pmc = prog->pmc;
|
||||
const struct clk_programmable_layout *layout = prog->layout;
|
||||
unsigned int pckr;
|
||||
|
||||
pres = (pmc_read(pmc, AT91_PMC_PCKR(prog->id)) >> layout->pres_shift) &
|
||||
PROG_PRES_MASK;
|
||||
return parent_rate >> pres;
|
||||
regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
|
||||
|
||||
return parent_rate >> PROG_PRES(prog->layout, pckr);
|
||||
}
|
||||
|
||||
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)
|
|||
{
|
||||
struct clk_programmable *prog = to_clk_programmable(hw);
|
||||
const struct clk_programmable_layout *layout = prog->layout;
|
||||
struct at91_pmc *pmc = prog->pmc;
|
||||
u32 tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id)) & ~layout->css_mask;
|
||||
unsigned int mask = layout->css_mask;
|
||||
unsigned int pckr = 0;
|
||||
|
||||
if (layout->have_slck_mck)
|
||||
tmp &= AT91_PMC_CSSMCK_MCK;
|
||||
mask |= AT91_PMC_CSSMCK_MCK;
|
||||
|
||||
if (index > layout->css_mask) {
|
||||
if (index > PROG_MAX_RM9200_CSS && layout->have_slck_mck) {
|
||||
tmp |= AT91_PMC_CSSMCK_MCK;
|
||||
return 0;
|
||||
} else {
|
||||
if (index > PROG_MAX_RM9200_CSS && !layout->have_slck_mck)
|
||||
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;
|
||||
}
|
||||
|
||||
static u8 clk_programmable_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
u32 tmp;
|
||||
u8 ret;
|
||||
struct clk_programmable *prog = to_clk_programmable(hw);
|
||||
struct at91_pmc *pmc = prog->pmc;
|
||||
const struct clk_programmable_layout *layout = prog->layout;
|
||||
unsigned int pckr;
|
||||
u8 ret;
|
||||
|
||||
tmp = pmc_read(pmc, AT91_PMC_PCKR(prog->id));
|
||||
ret = tmp & layout->css_mask;
|
||||
if (layout->have_slck_mck && (tmp & AT91_PMC_CSSMCK_MCK) && !ret)
|
||||
regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
|
||||
|
||||
ret = pckr & layout->css_mask;
|
||||
|
||||
if (layout->have_slck_mck && (pckr & AT91_PMC_CSSMCK_MCK) && !ret)
|
||||
ret = PROG_MAX_RM9200_CSS + 1;
|
||||
|
||||
return ret;
|
||||
|
@ -140,26 +137,27 @@ static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_programmable *prog = to_clk_programmable(hw);
|
||||
struct at91_pmc *pmc = prog->pmc;
|
||||
const struct clk_programmable_layout *layout = prog->layout;
|
||||
unsigned long div = parent_rate / rate;
|
||||
unsigned int pckr;
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
||||
shift = fls(div) - 1;
|
||||
|
||||
if (div != (1<<shift))
|
||||
if (div != (1 << shift))
|
||||
return -EINVAL;
|
||||
|
||||
if (shift >= PROG_PRES_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
pmc_write(pmc, AT91_PMC_PCKR(prog->id),
|
||||
tmp | (shift << layout->pres_shift));
|
||||
regmap_update_bits(prog->regmap, AT91_PMC_PCKR(prog->id),
|
||||
PROG_PRES_MASK << layout->pres_shift,
|
||||
shift << layout->pres_shift);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -173,7 +171,7 @@ static const struct clk_ops programmable_ops = {
|
|||
};
|
||||
|
||||
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,
|
||||
u8 num_parents, u8 id,
|
||||
const struct clk_programmable_layout *layout)
|
||||
|
@ -198,7 +196,7 @@ at91_clk_register_programmable(struct at91_pmc *pmc,
|
|||
prog->id = id;
|
||||
prog->layout = layout;
|
||||
prog->hw.init = &init;
|
||||
prog->pmc = pmc;
|
||||
prog->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &prog->hw);
|
||||
if (IS_ERR(clk))
|
||||
|
@ -226,7 +224,7 @@ static const struct clk_programmable_layout at91sam9x5_programmable_layout = {
|
|||
};
|
||||
|
||||
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)
|
||||
{
|
||||
int num;
|
||||
|
@ -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 *name;
|
||||
struct device_node *progclknp;
|
||||
struct regmap *regmap;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
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,
|
|||
if (!num || num > (PROG_ID_MAX + 1))
|
||||
return;
|
||||
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
for_each_child_of_node(np, progclknp) {
|
||||
if (of_property_read_u32(progclknp, "reg", &id))
|
||||
continue;
|
||||
|
@ -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))
|
||||
name = progclknp->name;
|
||||
|
||||
clk = at91_clk_register_programmable(pmc, name,
|
||||
clk = at91_clk_register_programmable(regmap, name,
|
||||
parent_names, num_parents,
|
||||
id, layout);
|
||||
if (IS_ERR(clk))
|
||||
|
@ -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,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91rm9200_clk_prog_setup(struct device_node *np)
|
||||
{
|
||||
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,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np)
|
||||
{
|
||||
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,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np)
|
||||
{
|
||||
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 @@
|
|||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "pmc.h"
|
||||
#include "sckc.h"
|
||||
|
@ -58,7 +52,7 @@ struct clk_slow_rc_osc {
|
|||
|
||||
struct clk_sam9260_slow {
|
||||
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)
|
||||
|
@ -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)
|
||||
{
|
||||
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 = {
|
||||
|
@ -397,7 +394,7 @@ static const struct clk_ops sam9260_slow_ops = {
|
|||
};
|
||||
|
||||
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 **parent_names,
|
||||
int num_parents)
|
||||
|
@ -406,7 +403,7 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
|
|||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
|
||||
if (!pmc || !name)
|
||||
if (!name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!parent_names || !num_parents)
|
||||
|
@ -423,7 +420,7 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
|
|||
init.flags = 0;
|
||||
|
||||
slowck->hw.init = &init;
|
||||
slowck->pmc = pmc;
|
||||
slowck->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &slowck->hw);
|
||||
if (IS_ERR(clk))
|
||||
|
@ -432,26 +429,32 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
|
|||
return clk;
|
||||
}
|
||||
|
||||
void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *parent_names[2];
|
||||
int num_parents;
|
||||
const char *name = np->name;
|
||||
struct regmap *regmap;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
if (num_parents != 2)
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
clk = at91_clk_register_sam9260_slow(pmc, name, parent_names,
|
||||
clk = at91_clk_register_sam9260_slow(regmap, name, parent_names,
|
||||
num_parents);
|
||||
if (IS_ERR(clk))
|
||||
return;
|
||||
|
||||
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 @@
|
|||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
|||
|
||||
struct at91sam9x5_clk_smd {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
#define to_at91sam9x5_clk_smd(hw) \
|
||||
|
@ -33,13 +33,13 @@ struct at91sam9x5_clk_smd {
|
|||
static unsigned long at91sam9x5_clk_smd_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 tmp;
|
||||
u8 smddiv;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
u32 tmp;
|
||||
struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
|
||||
struct at91_pmc *pmc = smd->pmc;
|
||||
|
||||
if (index > 1)
|
||||
return -EINVAL;
|
||||
tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMDS;
|
||||
if (index)
|
||||
tmp |= AT91_PMC_SMDS;
|
||||
pmc_write(pmc, AT91_PMC_SMD, tmp);
|
||||
|
||||
regmap_update_bits(smd->regmap, AT91_PMC_SMD, AT91_PMC_SMDS,
|
||||
index ? AT91_PMC_SMDS : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 at91sam9x5_clk_smd_get_parent(struct clk_hw *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,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 tmp;
|
||||
struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(hw);
|
||||
struct at91_pmc *pmc = smd->pmc;
|
||||
unsigned long div = parent_rate / rate;
|
||||
|
||||
if (parent_rate % rate || div < 1 || div > (SMD_MAX_DIV + 1))
|
||||
return -EINVAL;
|
||||
tmp = pmc_read(pmc, AT91_PMC_SMD) & ~AT91_PMC_SMD_DIV;
|
||||
tmp |= (div - 1) << SMD_DIV_SHIFT;
|
||||
pmc_write(pmc, AT91_PMC_SMD, tmp);
|
||||
|
||||
regmap_update_bits(smd->regmap, AT91_PMC_SMD, AT91_PMC_SMD_DIV,
|
||||
(div - 1) << SMD_DIV_SHIFT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -114,7 +112,7 @@ static const struct clk_ops at91sam9x5_smd_ops = {
|
|||
};
|
||||
|
||||
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)
|
||||
{
|
||||
struct at91sam9x5_clk_smd *smd;
|
||||
|
@ -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;
|
||||
|
||||
smd->hw.init = &init;
|
||||
smd->pmc = pmc;
|
||||
smd->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &smd->hw);
|
||||
if (IS_ERR(clk))
|
||||
|
@ -141,13 +139,13 @@ at91sam9x5_clk_register_smd(struct at91_pmc *pmc, const char *name,
|
|||
return clk;
|
||||
}
|
||||
|
||||
void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
int num_parents;
|
||||
const char *parent_names[SMD_SOURCE_MAX];
|
||||
const char *name = np->name;
|
||||
struct regmap *regmap;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX)
|
||||
|
@ -157,10 +155,16 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
|
|||
|
||||
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);
|
||||
if (IS_ERR(clk))
|
||||
return;
|
||||
|
||||
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 @@
|
|||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
|
@ -29,9 +24,7 @@
|
|||
#define to_clk_system(hw) container_of(hw, struct clk_system, hw)
|
||||
struct clk_system {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
unsigned int irq;
|
||||
wait_queue_head_t wait;
|
||||
struct regmap *regmap;
|
||||
u8 id;
|
||||
};
|
||||
|
||||
|
@ -39,58 +32,54 @@ static inline int is_pck(int id)
|
|||
{
|
||||
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);
|
||||
disable_irq_nosync(sys->irq);
|
||||
regmap_read(regmap, AT91_PMC_SR, &status);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return status & (1 << id) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int clk_system_prepare(struct clk_hw *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))
|
||||
return 0;
|
||||
|
||||
while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) {
|
||||
if (sys->irq) {
|
||||
enable_irq(sys->irq);
|
||||
wait_event(sys->wait,
|
||||
pmc_read(pmc, AT91_PMC_SR) & mask);
|
||||
} else
|
||||
cpu_relax();
|
||||
}
|
||||
while (!clk_system_ready(sys->regmap, sys->id))
|
||||
cpu_relax();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_system_unprepare(struct clk_hw *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)
|
||||
{
|
||||
struct clk_system *sys = to_clk_system(hw);
|
||||
struct at91_pmc *pmc = sys->pmc;
|
||||
unsigned int status;
|
||||
|
||||
if (!(pmc_read(pmc, AT91_PMC_SCSR) & (1 << sys->id)))
|
||||
regmap_read(sys->regmap, AT91_PMC_SCSR, &status);
|
||||
|
||||
if (!(status & (1 << sys->id)))
|
||||
return 0;
|
||||
|
||||
if (!is_pck(sys->id))
|
||||
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 = {
|
||||
|
@ -100,13 +89,12 @@ static const struct clk_ops system_ops = {
|
|||
};
|
||||
|
||||
static struct clk * __init
|
||||
at91_clk_register_system(struct at91_pmc *pmc, const char *name,
|
||||
const char *parent_name, u8 id, int irq)
|
||||
at91_clk_register_system(struct regmap *regmap, const char *name,
|
||||
const char *parent_name, u8 id)
|
||||
{
|
||||
struct clk_system *sys;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
if (!parent_name || id > SYSTEM_MAX_ID)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
@ -123,44 +111,33 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name,
|
|||
|
||||
sys->id = id;
|
||||
sys->hw.init = &init;
|
||||
sys->pmc = pmc;
|
||||
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);
|
||||
}
|
||||
}
|
||||
sys->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &sys->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
if (irq)
|
||||
free_irq(sys->irq, sys);
|
||||
if (IS_ERR(clk))
|
||||
kfree(sys);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
static void __init
|
||||
of_at91_clk_sys_setup(struct device_node *np, struct at91_pmc *pmc)
|
||||
static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
|
||||
{
|
||||
int num;
|
||||
int irq = 0;
|
||||
u32 id;
|
||||
struct clk *clk;
|
||||
const char *name;
|
||||
struct device_node *sysclknp;
|
||||
const char *parent_name;
|
||||
struct regmap *regmap;
|
||||
|
||||
num = of_get_child_count(np);
|
||||
if (num > (SYSTEM_MAX_ID + 1))
|
||||
return;
|
||||
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
for_each_child_of_node(np, sysclknp) {
|
||||
if (of_property_read_u32(sysclknp, "reg", &id))
|
||||
continue;
|
||||
|
@ -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))
|
||||
name = sysclknp->name;
|
||||
|
||||
if (is_pck(id))
|
||||
irq = irq_of_parse_and_map(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))
|
||||
continue;
|
||||
|
||||
of_clk_add_provider(sysclknp, of_clk_src_simple_get, clk);
|
||||
}
|
||||
}
|
||||
|
||||
void __init of_at91rm9200_clk_sys_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
{
|
||||
of_at91_clk_sys_setup(np, pmc);
|
||||
}
|
||||
CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system",
|
||||
of_at91rm9200_clk_sys_setup);
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
|||
|
||||
struct at91sam9x5_clk_usb {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
#define to_at91sam9x5_clk_usb(hw) \
|
||||
|
@ -35,7 +35,7 @@ struct at91sam9x5_clk_usb {
|
|||
|
||||
struct at91rm9200_clk_usb {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
struct regmap *regmap;
|
||||
u32 divisors[4];
|
||||
};
|
||||
|
||||
|
@ -45,13 +45,12 @@ struct at91rm9200_clk_usb {
|
|||
static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 tmp;
|
||||
u8 usbdiv;
|
||||
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);
|
||||
usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT;
|
||||
regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
|
||||
usbdiv = (usbr & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT;
|
||||
|
||||
return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1));
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
u32 tmp;
|
||||
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
|
||||
struct at91_pmc *pmc = usb->pmc;
|
||||
|
||||
if (index > 1)
|
||||
return -EINVAL;
|
||||
tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS;
|
||||
if (index)
|
||||
tmp |= AT91_PMC_USBS;
|
||||
pmc_write(pmc, AT91_PMC_USB, tmp);
|
||||
|
||||
regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS,
|
||||
index ? AT91_PMC_USBS : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *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,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 tmp;
|
||||
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
|
||||
struct at91_pmc *pmc = usb->pmc;
|
||||
unsigned long div;
|
||||
|
||||
if (!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)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV;
|
||||
tmp |= (div - 1) << SAM9X5_USB_DIV_SHIFT;
|
||||
pmc_write(pmc, AT91_PMC_USB, tmp);
|
||||
regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_OHCIUSBDIV,
|
||||
(div - 1) << SAM9X5_USB_DIV_SHIFT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -163,28 +159,28 @@ static const struct clk_ops at91sam9x5_usb_ops = {
|
|||
static int at91sam9n12_clk_usb_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
|
||||
struct at91_pmc *pmc = usb->pmc;
|
||||
|
||||
pmc_write(pmc, AT91_PMC_USB,
|
||||
pmc_read(pmc, AT91_PMC_USB) | AT91_PMC_USBS);
|
||||
regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS,
|
||||
AT91_PMC_USBS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void at91sam9n12_clk_usb_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
|
||||
struct at91_pmc *pmc = usb->pmc;
|
||||
|
||||
pmc_write(pmc, AT91_PMC_USB,
|
||||
pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_USBS);
|
||||
regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS, 0);
|
||||
}
|
||||
|
||||
static int at91sam9n12_clk_usb_is_enabled(struct clk_hw *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 = {
|
||||
|
@ -197,7 +193,7 @@ static const struct clk_ops at91sam9n12_usb_ops = {
|
|||
};
|
||||
|
||||
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)
|
||||
{
|
||||
struct at91sam9x5_clk_usb *usb;
|
||||
|
@ -216,7 +212,7 @@ at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name,
|
|||
CLK_SET_RATE_PARENT;
|
||||
|
||||
usb->hw.init = &init;
|
||||
usb->pmc = pmc;
|
||||
usb->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &usb->hw);
|
||||
if (IS_ERR(clk))
|
||||
|
@ -226,7 +222,7 @@ at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name,
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct at91sam9x5_clk_usb *usb;
|
||||
|
@ -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;
|
||||
|
||||
usb->hw.init = &init;
|
||||
usb->pmc = pmc;
|
||||
usb->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &usb->hw);
|
||||
if (IS_ERR(clk))
|
||||
|
@ -257,12 +253,12 @@ static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk_hw *hw,
|
|||
unsigned long parent_rate)
|
||||
{
|
||||
struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
|
||||
struct at91_pmc *pmc = usb->pmc;
|
||||
u32 tmp;
|
||||
unsigned int pllbr;
|
||||
u8 usbdiv;
|
||||
|
||||
tmp = pmc_read(pmc, AT91_CKGR_PLLBR);
|
||||
usbdiv = (tmp & AT91_PMC_USBDIV) >> RM9200_USB_DIV_SHIFT;
|
||||
regmap_read(usb->regmap, AT91_CKGR_PLLBR, &pllbr);
|
||||
|
||||
usbdiv = (pllbr & AT91_PMC_USBDIV) >> RM9200_USB_DIV_SHIFT;
|
||||
if (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,
|
|||
static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 tmp;
|
||||
int i;
|
||||
struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
|
||||
struct at91_pmc *pmc = usb->pmc;
|
||||
unsigned long div;
|
||||
|
||||
if (!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++) {
|
||||
if (usb->divisors[i] == div) {
|
||||
tmp = pmc_read(pmc, AT91_CKGR_PLLBR) &
|
||||
~AT91_PMC_USBDIV;
|
||||
tmp |= i << RM9200_USB_DIV_SHIFT;
|
||||
pmc_write(pmc, AT91_CKGR_PLLBR, tmp);
|
||||
regmap_update_bits(usb->regmap, AT91_CKGR_PLLBR,
|
||||
AT91_PMC_USBDIV,
|
||||
i << RM9200_USB_DIV_SHIFT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -341,7 +335,7 @@ static const struct clk_ops at91rm9200_usb_ops = {
|
|||
};
|
||||
|
||||
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)
|
||||
{
|
||||
struct at91rm9200_clk_usb *usb;
|
||||
|
@ -359,7 +353,7 @@ at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name,
|
|||
init.flags = CLK_SET_RATE_PARENT;
|
||||
|
||||
usb->hw.init = &init;
|
||||
usb->pmc = pmc;
|
||||
usb->regmap = regmap;
|
||||
memcpy(usb->divisors, divisors, sizeof(usb->divisors));
|
||||
|
||||
clk = clk_register(NULL, &usb->hw);
|
||||
|
@ -369,13 +363,13 @@ at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name,
|
|||
return clk;
|
||||
}
|
||||
|
||||
void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
int num_parents;
|
||||
const char *parent_names[USB_SOURCE_MAX];
|
||||
const char *name = np->name;
|
||||
struct regmap *regmap;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
if (num_parents <= 0 || num_parents > USB_SOURCE_MAX)
|
||||
|
@ -385,19 +379,26 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
|
|||
|
||||
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))
|
||||
return;
|
||||
|
||||
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,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
struct regmap *regmap;
|
||||
|
||||
parent_name = of_clk_get_parent_name(np, 0);
|
||||
if (!parent_name)
|
||||
|
@ -405,20 +406,26 @@ void __init of_at91sam9n12_clk_usb_setup(struct device_node *np,
|
|||
|
||||
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))
|
||||
return;
|
||||
|
||||
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,
|
||||
struct at91_pmc *pmc)
|
||||
static void __init of_at91rm9200_clk_usb_setup(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
u32 divisors[4] = {0, 0, 0, 0};
|
||||
struct regmap *regmap;
|
||||
|
||||
parent_name = of_clk_get_parent_name(np, 0);
|
||||
if (!parent_name)
|
||||
|
@ -430,9 +437,15 @@ void __init of_at91rm9200_clk_usb_setup(struct device_node *np,
|
|||
|
||||
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))
|
||||
return;
|
||||
|
||||
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 @@
|
|||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
|
@ -26,37 +21,30 @@
|
|||
|
||||
struct clk_utmi {
|
||||
struct clk_hw hw;
|
||||
struct at91_pmc *pmc;
|
||||
unsigned int irq;
|
||||
wait_queue_head_t wait;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
#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);
|
||||
disable_irq_nosync(utmi->irq);
|
||||
regmap_read(regmap, AT91_PMC_SR, &status);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return status & AT91_PMC_LOCKU;
|
||||
}
|
||||
|
||||
static int clk_utmi_prepare(struct clk_hw *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 |
|
||||
AT91_PMC_UPLLCOUNT | AT91_PMC_BIASEN;
|
||||
unsigned int uckr = AT91_PMC_UPLLEN | 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)) {
|
||||
enable_irq(utmi->irq);
|
||||
wait_event(utmi->wait,
|
||||
pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_LOCKU);
|
||||
}
|
||||
while (!clk_utmi_ready(utmi->regmap))
|
||||
cpu_relax();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -64,18 +52,15 @@ static int clk_utmi_prepare(struct clk_hw *hw)
|
|||
static int clk_utmi_is_prepared(struct clk_hw *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)
|
||||
{
|
||||
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,
|
||||
|
@ -93,10 +78,9 @@ static const struct clk_ops utmi_ops = {
|
|||
};
|
||||
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
struct clk_utmi *utmi;
|
||||
struct clk *clk = NULL;
|
||||
struct clk_init_data init;
|
||||
|
@ -112,52 +96,36 @@ at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq,
|
|||
init.flags = CLK_SET_RATE_GATE;
|
||||
|
||||
utmi->hw.init = &init;
|
||||
utmi->pmc = pmc;
|
||||
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);
|
||||
}
|
||||
utmi->regmap = regmap;
|
||||
|
||||
clk = clk_register(NULL, &utmi->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
free_irq(utmi->irq, utmi);
|
||||
if (IS_ERR(clk))
|
||||
kfree(utmi);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
static void __init
|
||||
of_at91_clk_utmi_setup(struct device_node *np, struct at91_pmc *pmc)
|
||||
static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
|
||||
{
|
||||
unsigned int irq;
|
||||
struct clk *clk;
|
||||
const char *parent_name;
|
||||
const char *name = np->name;
|
||||
struct regmap *regmap;
|
||||
|
||||
parent_name = of_clk_get_parent_name(np, 0);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (!irq)
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
return;
|
||||
|
||||
clk = at91_clk_register_utmi(pmc, irq, name, parent_name);
|
||||
clk = at91_clk_register_utmi(regmap, name, parent_name);
|
||||
if (IS_ERR(clk))
|
||||
return;
|
||||
|
||||
of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
return;
|
||||
}
|
||||
|
||||
void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc)
|
||||
{
|
||||
of_at91_clk_utmi_setup(np, pmc);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi",
|
||||
of_at91sam9x5_clk_utmi_setup);
|
||||
|
|
|
@ -12,36 +12,13 @@
|
|||
#include <linux/clkdev.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <asm/proc-fns.h>
|
||||
|
||||
#include "pmc.h"
|
||||
|
||||
void __iomem *at91_pmc_base;
|
||||
EXPORT_SYMBOL_GPL(at91_pmc_base);
|
||||
|
||||
void at91rm9200_idle(void)
|
||||
{
|
||||
/*
|
||||
* Disable the processor clock. The processor will be automatically
|
||||
* re-enabled by an interrupt or by a reset.
|
||||
*/
|
||||
at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
|
||||
}
|
||||
|
||||
void at91sam9_idle(void)
|
||||
{
|
||||
at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
|
||||
cpu_do_idle();
|
||||
}
|
||||
|
||||
int of_at91_get_clk_range(struct device_node *np, const char *propname,
|
||||
struct clk_range *range)
|
||||
{
|
||||
|
@ -64,402 +41,3 @@ int of_at91_get_clk_range(struct device_node *np, const char *propname,
|
|||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_at91_get_clk_range);
|
||||
|
||||
static void pmc_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
pmc_write(pmc, AT91_PMC_IDR, 1 << d->hwirq);
|
||||
}
|
||||
|
||||
static void pmc_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
pmc_write(pmc, AT91_PMC_IER, 1 << d->hwirq);
|
||||
}
|
||||
|
||||
static int pmc_irq_set_type(struct irq_data *d, unsigned type)
|
||||
{
|
||||
if (type != IRQ_TYPE_LEVEL_HIGH) {
|
||||
pr_warn("PMC: type not supported (support only IRQ_TYPE_LEVEL_HIGH type)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pmc_irq_suspend(struct irq_data *d)
|
||||
{
|
||||
struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
pmc->imr = pmc_read(pmc, AT91_PMC_IMR);
|
||||
pmc_write(pmc, AT91_PMC_IDR, pmc->imr);
|
||||
}
|
||||
|
||||
static void pmc_irq_resume(struct irq_data *d)
|
||||
{
|
||||
struct at91_pmc *pmc = irq_data_get_irq_chip_data(d);
|
||||
|
||||
pmc_write(pmc, AT91_PMC_IER, pmc->imr);
|
||||
}
|
||||
|
||||
static struct irq_chip pmc_irq = {
|
||||
.name = "PMC",
|
||||
.irq_disable = pmc_irq_mask,
|
||||
.irq_mask = pmc_irq_mask,
|
||||
.irq_unmask = pmc_irq_unmask,
|
||||
.irq_set_type = pmc_irq_set_type,
|
||||
.irq_suspend = pmc_irq_suspend,
|
||||
.irq_resume = pmc_irq_resume,
|
||||
};
|
||||
|
||||
static struct lock_class_key pmc_lock_class;
|
||||
|
||||
static int pmc_irq_map(struct irq_domain *h, unsigned int virq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
struct at91_pmc *pmc = h->host_data;
|
||||
|
||||
irq_set_lockdep_class(virq, &pmc_lock_class);
|
||||
|
||||
irq_set_chip_and_handler(virq, &pmc_irq,
|
||||
handle_level_irq);
|
||||
irq_set_chip_data(virq, pmc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmc_irq_domain_xlate(struct irq_domain *d,
|
||||
struct device_node *ctrlr,
|
||||
const u32 *intspec, unsigned int intsize,
|
||||
irq_hw_number_t *out_hwirq,
|
||||
unsigned int *out_type)
|
||||
{
|
||||
struct at91_pmc *pmc = d->host_data;
|
||||
const struct at91_pmc_caps *caps = pmc->caps;
|
||||
|
||||
if (WARN_ON(intsize < 1))
|
||||
return -EINVAL;
|
||||
|
||||
*out_hwirq = intspec[0];
|
||||
|
||||
if (!(caps->available_irqs & (1 << *out_hwirq)))
|
||||
return -EINVAL;
|
||||
|
||||
*out_type = IRQ_TYPE_LEVEL_HIGH;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops pmc_irq_ops = {
|
||||
.map = pmc_irq_map,
|
||||
.xlate = pmc_irq_domain_xlate,
|
||||
};
|
||||
|
||||
static irqreturn_t pmc_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct at91_pmc *pmc = (struct at91_pmc *)data;
|
||||
unsigned long sr;
|
||||
int n;
|
||||
|
||||
sr = pmc_read(pmc, AT91_PMC_SR) & pmc_read(pmc, AT91_PMC_IMR);
|
||||
if (!sr)
|
||||
return IRQ_NONE;
|
||||
|
||||
for_each_set_bit(n, &sr, BITS_PER_LONG)
|
||||
generic_handle_irq(irq_find_mapping(pmc->irqdomain, n));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct at91_pmc_caps at91rm9200_caps = {
|
||||
.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB |
|
||||
AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
|
||||
AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY |
|
||||
AT91_PMC_PCK3RDY,
|
||||
};
|
||||
|
||||
static const struct at91_pmc_caps at91sam9260_caps = {
|
||||
.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB |
|
||||
AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
|
||||
AT91_PMC_PCK1RDY,
|
||||
};
|
||||
|
||||
static const struct at91_pmc_caps at91sam9g45_caps = {
|
||||
.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
|
||||
AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
|
||||
AT91_PMC_PCK1RDY,
|
||||
};
|
||||
|
||||
static const struct at91_pmc_caps at91sam9n12_caps = {
|
||||
.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB |
|
||||
AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
|
||||
AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS |
|
||||
AT91_PMC_MOSCRCS | AT91_PMC_CFDEV,
|
||||
};
|
||||
|
||||
static const struct at91_pmc_caps at91sam9x5_caps = {
|
||||
.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
|
||||
AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
|
||||
AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS |
|
||||
AT91_PMC_MOSCRCS | AT91_PMC_CFDEV,
|
||||
};
|
||||
|
||||
static const struct at91_pmc_caps sama5d2_caps = {
|
||||
.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
|
||||
AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
|
||||
AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY |
|
||||
AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS |
|
||||
AT91_PMC_CFDEV | AT91_PMC_GCKRDY,
|
||||
};
|
||||
|
||||
static const struct at91_pmc_caps sama5d3_caps = {
|
||||
.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
|
||||
AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
|
||||
AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY |
|
||||
AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS |
|
||||
AT91_PMC_CFDEV,
|
||||
};
|
||||
|
||||
static struct at91_pmc *__init at91_pmc_init(struct device_node *np,
|
||||
void __iomem *regbase, int virq,
|
||||
const struct at91_pmc_caps *caps)
|
||||
{
|
||||
struct at91_pmc *pmc;
|
||||
|
||||
if (!regbase || !virq || !caps)
|
||||
return NULL;
|
||||
|
||||
at91_pmc_base = regbase;
|
||||
|
||||
pmc = kzalloc(sizeof(*pmc), GFP_KERNEL);
|
||||
if (!pmc)
|
||||
return NULL;
|
||||
|
||||
spin_lock_init(&pmc->lock);
|
||||
pmc->regbase = regbase;
|
||||
pmc->virq = virq;
|
||||
pmc->caps = caps;
|
||||
|
||||
pmc->irqdomain = irq_domain_add_linear(np, 32, &pmc_irq_ops, pmc);
|
||||
|
||||
if (!pmc->irqdomain)
|
||||
goto out_free_pmc;
|
||||
|
||||
pmc_write(pmc, AT91_PMC_IDR, 0xffffffff);
|
||||
if (request_irq(pmc->virq, pmc_irq_handler,
|
||||
IRQF_SHARED | IRQF_COND_SUSPEND, "pmc", pmc))
|
||||
goto out_remove_irqdomain;
|
||||
|
||||
return pmc;
|
||||
|
||||
out_remove_irqdomain:
|
||||
irq_domain_remove(pmc->irqdomain);
|
||||
out_free_pmc:
|
||||
kfree(pmc);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct of_device_id pmc_clk_ids[] __initconst = {
|
||||
/* Slow oscillator */
|
||||
{
|
||||
.compatible = "atmel,at91sam9260-clk-slow",
|
||||
.data = of_at91sam9260_clk_slow_setup,
|
||||
},
|
||||
/* Main clock */
|
||||
{
|
||||
.compatible = "atmel,at91rm9200-clk-main-osc",
|
||||
.data = of_at91rm9200_clk_main_osc_setup,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91sam9x5-clk-main-rc-osc",
|
||||
.data = of_at91sam9x5_clk_main_rc_osc_setup,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91rm9200-clk-main",
|
||||
.data = of_at91rm9200_clk_main_setup,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91sam9x5-clk-main",
|
||||
.data = of_at91sam9x5_clk_main_setup,
|
||||
},
|
||||
/* PLL clocks */
|
||||
{
|
||||
.compatible = "atmel,at91rm9200-clk-pll",
|
||||
.data = of_at91rm9200_clk_pll_setup,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91sam9g45-clk-pll",
|
||||
.data = of_at91sam9g45_clk_pll_setup,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91sam9g20-clk-pllb",
|
||||
.data = of_at91sam9g20_clk_pllb_setup,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,sama5d3-clk-pll",
|
||||
.data = of_sama5d3_clk_pll_setup,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91sam9x5-clk-plldiv",
|
||||
.data = of_at91sam9x5_clk_plldiv_setup,
|
||||
},
|
||||
/* Master clock */
|
||||
{
|
||||
.compatible = "atmel,at91rm9200-clk-master",
|
||||
.data = of_at91rm9200_clk_master_setup,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91sam9x5-clk-master",
|
||||
.data = of_at91sam9x5_clk_master_setup,
|
||||
},
|
||||
/* System clocks */
|
||||
{
|
||||
.compatible = "atmel,at91rm9200-clk-system",
|
||||
.data = of_at91rm9200_clk_sys_setup,
|
||||
},
|
||||
/* Peripheral clocks */
|
||||
{
|
||||
.compatible = "atmel,at91rm9200-clk-peripheral",
|
||||
.data = of_at91rm9200_clk_periph_setup,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91sam9x5-clk-peripheral",
|
||||
.data = of_at91sam9x5_clk_periph_setup,
|
||||
},
|
||||
/* Programmable clocks */
|
||||
{
|
||||
.compatible = "atmel,at91rm9200-clk-programmable",
|
||||
.data = of_at91rm9200_clk_prog_setup,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91sam9g45-clk-programmable",
|
||||
.data = of_at91sam9g45_clk_prog_setup,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91sam9x5-clk-programmable",
|
||||
.data = of_at91sam9x5_clk_prog_setup,
|
||||
},
|
||||
/* UTMI clock */
|
||||
#if defined(CONFIG_HAVE_AT91_UTMI)
|
||||
{
|
||||
.compatible = "atmel,at91sam9x5-clk-utmi",
|
||||
.data = of_at91sam9x5_clk_utmi_setup,
|
||||
},
|
||||
#endif
|
||||
/* USB clock */
|
||||
#if defined(CONFIG_HAVE_AT91_USB_CLK)
|
||||
{
|
||||
.compatible = "atmel,at91rm9200-clk-usb",
|
||||
.data = of_at91rm9200_clk_usb_setup,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91sam9x5-clk-usb",
|
||||
.data = of_at91sam9x5_clk_usb_setup,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91sam9n12-clk-usb",
|
||||
.data = of_at91sam9n12_clk_usb_setup,
|
||||
},
|
||||
#endif
|
||||
/* SMD clock */
|
||||
#if defined(CONFIG_HAVE_AT91_SMD)
|
||||
{
|
||||
.compatible = "atmel,at91sam9x5-clk-smd",
|
||||
.data = of_at91sam9x5_clk_smd_setup,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_HAVE_AT91_H32MX)
|
||||
{
|
||||
.compatible = "atmel,sama5d4-clk-h32mx",
|
||||
.data = of_sama5d4_clk_h32mx_setup,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_HAVE_AT91_GENERATED_CLK)
|
||||
{
|
||||
.compatible = "atmel,sama5d2-clk-generated",
|
||||
.data = of_sama5d2_clk_generated_setup,
|
||||
},
|
||||
#endif
|
||||
{ /*sentinel*/ }
|
||||
};
|
||||
|
||||
static void __init of_at91_pmc_setup(struct device_node *np,
|
||||
const struct at91_pmc_caps *caps)
|
||||
{
|
||||
struct at91_pmc *pmc;
|
||||
struct device_node *childnp;
|
||||
void (*clk_setup)(struct device_node *, struct at91_pmc *);
|
||||
const struct of_device_id *clk_id;
|
||||
void __iomem *regbase = of_iomap(np, 0);
|
||||
int virq;
|
||||
|
||||
if (!regbase)
|
||||
return;
|
||||
|
||||
virq = irq_of_parse_and_map(np, 0);
|
||||
if (!virq)
|
||||
return;
|
||||
|
||||
pmc = at91_pmc_init(np, regbase, virq, caps);
|
||||
if (!pmc)
|
||||
return;
|
||||
for_each_child_of_node(np, childnp) {
|
||||
clk_id = of_match_node(pmc_clk_ids, childnp);
|
||||
if (!clk_id)
|
||||
continue;
|
||||
clk_setup = clk_id->data;
|
||||
clk_setup(childnp, pmc);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init of_at91rm9200_pmc_setup(struct device_node *np)
|
||||
{
|
||||
of_at91_pmc_setup(np, &at91rm9200_caps);
|
||||
}
|
||||
CLK_OF_DECLARE(at91rm9200_clk_pmc, "atmel,at91rm9200-pmc",
|
||||
of_at91rm9200_pmc_setup);
|
||||
|
||||
static void __init of_at91sam9260_pmc_setup(struct device_node *np)
|
||||
{
|
||||
of_at91_pmc_setup(np, &at91sam9260_caps);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9260_clk_pmc, "atmel,at91sam9260-pmc",
|
||||
of_at91sam9260_pmc_setup);
|
||||
|
||||
static void __init of_at91sam9g45_pmc_setup(struct device_node *np)
|
||||
{
|
||||
of_at91_pmc_setup(np, &at91sam9g45_caps);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9g45_clk_pmc, "atmel,at91sam9g45-pmc",
|
||||
of_at91sam9g45_pmc_setup);
|
||||
|
||||
static void __init of_at91sam9n12_pmc_setup(struct device_node *np)
|
||||
{
|
||||
of_at91_pmc_setup(np, &at91sam9n12_caps);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9n12_clk_pmc, "atmel,at91sam9n12-pmc",
|
||||
of_at91sam9n12_pmc_setup);
|
||||
|
||||
static void __init of_at91sam9x5_pmc_setup(struct device_node *np)
|
||||
{
|
||||
of_at91_pmc_setup(np, &at91sam9x5_caps);
|
||||
}
|
||||
CLK_OF_DECLARE(at91sam9x5_clk_pmc, "atmel,at91sam9x5-pmc",
|
||||
of_at91sam9x5_pmc_setup);
|
||||
|
||||
static void __init of_sama5d2_pmc_setup(struct device_node *np)
|
||||
{
|
||||
of_at91_pmc_setup(np, &sama5d2_caps);
|
||||
}
|
||||
CLK_OF_DECLARE(sama5d2_clk_pmc, "atmel,sama5d2-pmc",
|
||||
of_sama5d2_pmc_setup);
|
||||
|
||||
static void __init of_sama5d3_pmc_setup(struct device_node *np)
|
||||
{
|
||||
of_at91_pmc_setup(np, &sama5d3_caps);
|
||||
}
|
||||
CLK_OF_DECLARE(sama5d3_clk_pmc, "atmel,sama5d3-pmc",
|
||||
of_sama5d3_pmc_setup);
|
||||
|
|
|
@ -14,8 +14,11 @@
|
|||
|
||||
#include <linux/io.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
extern spinlock_t pmc_pcr_lock;
|
||||
|
||||
struct clk_range {
|
||||
unsigned long min;
|
||||
unsigned long max;
|
||||
|
@ -23,102 +26,7 @@ struct clk_range {
|
|||
|
||||
#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,
|
||||
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_ */
|
||||
|
|
|
@ -576,10 +576,8 @@ static struct cpufreq_driver s5pv210_driver = {
|
|||
.get = cpufreq_generic_get,
|
||||
.init = s5pv210_cpu_init,
|
||||
.name = "s5pv210",
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = cpufreq_generic_suspend,
|
||||
.resume = cpufreq_generic_suspend, /* We need to set SLEEP FREQ again */
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct notifier_block s5pv210_cpufreq_reboot_notifier = {
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
#define FW_REV_MINOR(x) (((x) & FW_REV_MINOR_MASK) >> FW_REV_MINOR_BITS)
|
||||
#define FW_REV_PATCH(x) ((x) & FW_REV_PATCH_MASK)
|
||||
|
||||
#define MAX_RX_TIMEOUT (msecs_to_jiffies(20))
|
||||
#define MAX_RX_TIMEOUT (msecs_to_jiffies(30))
|
||||
|
||||
enum scpi_error_codes {
|
||||
SCPI_SUCCESS = 0, /* Success */
|
||||
|
@ -231,7 +231,8 @@ struct _scpi_sensor_info {
|
|||
};
|
||||
|
||||
struct sensor_value {
|
||||
__le32 val;
|
||||
__le32 lo_val;
|
||||
__le32 hi_val;
|
||||
} __packed;
|
||||
|
||||
static struct scpi_drvinfo *scpi_info;
|
||||
|
@ -373,7 +374,7 @@ static int scpi_send_message(u8 cmd, void *tx_buf, unsigned int tx_len,
|
|||
ret = -ETIMEDOUT;
|
||||
else
|
||||
/* first status word */
|
||||
ret = le32_to_cpu(msg->status);
|
||||
ret = msg->status;
|
||||
out:
|
||||
if (ret < 0 && rx_buf) /* remove entry from the list if timed-out */
|
||||
scpi_process_cmd(scpi_chan, msg->cmd);
|
||||
|
@ -525,15 +526,17 @@ static int scpi_sensor_get_info(u16 sensor_id, struct scpi_sensor_info *info)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int scpi_sensor_get_value(u16 sensor, u32 *val)
|
||||
int scpi_sensor_get_value(u16 sensor, u64 *val)
|
||||
{
|
||||
__le16 id = cpu_to_le16(sensor);
|
||||
struct sensor_value buf;
|
||||
int ret;
|
||||
|
||||
ret = scpi_send_message(SCPI_CMD_SENSOR_VALUE, &sensor, sizeof(sensor),
|
||||
ret = scpi_send_message(SCPI_CMD_SENSOR_VALUE, &id, sizeof(id),
|
||||
&buf, sizeof(buf));
|
||||
if (!ret)
|
||||
*val = le32_to_cpu(buf.val);
|
||||
*val = (u64)le32_to_cpu(buf.hi_val) << 32 |
|
||||
le32_to_cpu(buf.lo_val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -699,7 +702,7 @@ static int scpi_probe(struct platform_device *pdev)
|
|||
cl->rx_callback = scpi_handle_remote_msg;
|
||||
cl->tx_prepare = scpi_tx_prepare;
|
||||
cl->tx_block = true;
|
||||
cl->tx_tout = 50;
|
||||
cl->tx_tout = 20;
|
||||
cl->knows_txdone = false; /* controller can't ack */
|
||||
|
||||
INIT_LIST_HEAD(&pchan->rx_pending);
|
||||
|
|
|
@ -52,7 +52,7 @@ static int scpi_read_temp(void *dev, int *temp)
|
|||
struct scpi_sensors *scpi_sensors = zone->scpi_sensors;
|
||||
struct scpi_ops *scpi_ops = scpi_sensors->scpi_ops;
|
||||
struct sensor_data *sensor = &scpi_sensors->data[zone->sensor_id];
|
||||
u32 value;
|
||||
u64 value;
|
||||
int ret;
|
||||
|
||||
ret = scpi_ops->sensor_get_value(sensor->info.sensor_id, &value);
|
||||
|
@ -70,7 +70,7 @@ scpi_show_sensor(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
struct scpi_sensors *scpi_sensors = dev_get_drvdata(dev);
|
||||
struct scpi_ops *scpi_ops = scpi_sensors->scpi_ops;
|
||||
struct sensor_data *sensor;
|
||||
u32 value;
|
||||
u64 value;
|
||||
int ret;
|
||||
|
||||
sensor = container_of(attr, struct sensor_data, dev_attr_input);
|
||||
|
@ -79,7 +79,7 @@ scpi_show_sensor(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%u\n", value);
|
||||
return sprintf(buf, "%llu\n", value);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
@ -114,6 +114,7 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
|
|||
{
|
||||
u16 nr_sensors, i;
|
||||
int num_temp = 0, num_volt = 0, num_current = 0, num_power = 0;
|
||||
int num_energy = 0;
|
||||
struct scpi_ops *scpi_ops;
|
||||
struct device *hwdev, *dev = &pdev->dev;
|
||||
struct scpi_sensors *scpi_sensors;
|
||||
|
@ -182,6 +183,13 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
|
|||
"power%d_label", num_power + 1);
|
||||
num_power++;
|
||||
break;
|
||||
case ENERGY:
|
||||
snprintf(sensor->input, sizeof(sensor->input),
|
||||
"energy%d_input", num_energy + 1);
|
||||
snprintf(sensor->label, sizeof(sensor->input),
|
||||
"energy%d_label", num_energy + 1);
|
||||
num_energy++;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -541,9 +541,20 @@ static void gpmc_cs_show_timings(int cs, const char *desc)
|
|||
GPMC_GET_TICKS(GPMC_CS_CONFIG3, 0, 3, "adv-on-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG3, 8, 12, "adv-rd-off-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG3, 16, 20, "adv-wr-off-ns");
|
||||
if (gpmc_capability & GPMC_HAS_MUX_AAD) {
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG3, 4, 6, "adv-aad-mux-on-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG3, 24, 26,
|
||||
"adv-aad-mux-rd-off-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG3, 28, 30,
|
||||
"adv-aad-mux-wr-off-ns");
|
||||
}
|
||||
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG4, 0, 3, "oe-on-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG4, 8, 12, "oe-off-ns");
|
||||
if (gpmc_capability & GPMC_HAS_MUX_AAD) {
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG4, 4, 6, "oe-aad-mux-on-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG4, 13, 15, "oe-aad-mux-off-ns");
|
||||
}
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG4, 16, 19, "we-on-ns");
|
||||
GPMC_GET_TICKS(GPMC_CS_CONFIG4, 24, 28, "we-off-ns");
|
||||
|
||||
|
@ -734,9 +745,18 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t,
|
|||
GPMC_SET_ONE(GPMC_CS_CONFIG3, 0, 3, adv_on);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG3, 8, 12, adv_rd_off);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG3, 16, 20, adv_wr_off);
|
||||
if (gpmc_capability & GPMC_HAS_MUX_AAD) {
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG3, 4, 6, adv_aad_mux_on);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG3, 24, 26, adv_aad_mux_rd_off);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG3, 28, 30, adv_aad_mux_wr_off);
|
||||
}
|
||||
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG4, 0, 3, oe_on);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG4, 8, 12, oe_off);
|
||||
if (gpmc_capability & GPMC_HAS_MUX_AAD) {
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG4, 4, 6, oe_aad_mux_on);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG4, 13, 15, oe_aad_mux_off);
|
||||
}
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG4, 16, 19, we_on);
|
||||
GPMC_SET_ONE(GPMC_CS_CONFIG4, 24, 28, we_off);
|
||||
|
||||
|
@ -1722,6 +1742,12 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
|
|||
of_property_read_u32(np, "gpmc,adv-on-ns", &gpmc_t->adv_on);
|
||||
of_property_read_u32(np, "gpmc,adv-rd-off-ns", &gpmc_t->adv_rd_off);
|
||||
of_property_read_u32(np, "gpmc,adv-wr-off-ns", &gpmc_t->adv_wr_off);
|
||||
of_property_read_u32(np, "gpmc,adv-aad-mux-on-ns",
|
||||
&gpmc_t->adv_aad_mux_on);
|
||||
of_property_read_u32(np, "gpmc,adv-aad-mux-rd-off-ns",
|
||||
&gpmc_t->adv_aad_mux_rd_off);
|
||||
of_property_read_u32(np, "gpmc,adv-aad-mux-wr-off-ns",
|
||||
&gpmc_t->adv_aad_mux_wr_off);
|
||||
|
||||
/* WE signal timings */
|
||||
of_property_read_u32(np, "gpmc,we-on-ns", &gpmc_t->we_on);
|
||||
|
@ -1730,6 +1756,10 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
|
|||
/* OE signal timings */
|
||||
of_property_read_u32(np, "gpmc,oe-on-ns", &gpmc_t->oe_on);
|
||||
of_property_read_u32(np, "gpmc,oe-off-ns", &gpmc_t->oe_off);
|
||||
of_property_read_u32(np, "gpmc,oe-aad-mux-on-ns",
|
||||
&gpmc_t->oe_aad_mux_on);
|
||||
of_property_read_u32(np, "gpmc,oe-aad-mux-off-ns",
|
||||
&gpmc_t->oe_aad_mux_off);
|
||||
|
||||
/* access and cycle timings */
|
||||
of_property_read_u32(np, "gpmc,page-burst-access-ns",
|
||||
|
|
|
@ -2,6 +2,7 @@ obj-y += core.o
|
|||
obj-$(CONFIG_ARCH_LPC18XX) += reset-lpc18xx.o
|
||||
obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
|
||||
obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
|
||||
obj-$(CONFIG_MACH_PISTACHIO) += reset-pistachio.o
|
||||
obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
|
||||
obj-$(CONFIG_ARCH_STI) += sti/
|
||||
obj-$(CONFIG_ARCH_HISI) += hisilicon/
|
||||
|
|
|
@ -45,9 +45,6 @@ struct reset_control {
|
|||
static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
|
||||
const struct of_phandle_args *reset_spec)
|
||||
{
|
||||
if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
|
||||
return -EINVAL;
|
||||
|
||||
if (reset_spec->args[0] >= rcdev->nr_resets)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -152,7 +149,7 @@ EXPORT_SYMBOL_GPL(reset_control_status);
|
|||
struct reset_control *of_reset_control_get_by_index(struct device_node *node,
|
||||
int index)
|
||||
{
|
||||
struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
|
||||
struct reset_control *rstc;
|
||||
struct reset_controller_dev *r, *rcdev;
|
||||
struct of_phandle_args args;
|
||||
int rstc_id;
|
||||
|
@ -178,6 +175,11 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
|
|||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
|
||||
mutex_unlock(&reset_controller_list_mutex);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
rstc_id = rcdev->of_xlate(rcdev, &args);
|
||||
if (rstc_id < 0) {
|
||||
mutex_unlock(&reset_controller_list_mutex);
|
||||
|
|
|
@ -57,7 +57,7 @@ static int hi6220_reset_deassert(struct reset_controller_dev *rc_dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct reset_control_ops hi6220_reset_ops = {
|
||||
static const struct reset_control_ops hi6220_reset_ops = {
|
||||
.assert = hi6220_reset_assert,
|
||||
.deassert = hi6220_reset_deassert,
|
||||
};
|
||||
|
@ -83,9 +83,7 @@ static int hi6220_reset_probe(struct platform_device *pdev)
|
|||
data->rc_dev.ops = &hi6220_reset_ops;
|
||||
data->rc_dev.of_node = pdev->dev.of_node;
|
||||
|
||||
reset_controller_register(&data->rc_dev);
|
||||
|
||||
return 0;
|
||||
return reset_controller_register(&data->rc_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id hi6220_reset_match[] = {
|
||||
|
|
|
@ -70,7 +70,7 @@ static int ath79_reset_status(struct reset_controller_dev *rcdev,
|
|||
return !!(val & BIT(id));
|
||||
}
|
||||
|
||||
static struct reset_control_ops ath79_reset_ops = {
|
||||
static const struct reset_control_ops ath79_reset_ops = {
|
||||
.assert = ath79_reset_assert,
|
||||
.deassert = ath79_reset_deassert,
|
||||
.status = ath79_reset_status,
|
||||
|
|
|
@ -46,7 +46,7 @@ static int berlin_reset_reset(struct reset_controller_dev *rcdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct reset_control_ops berlin_reset_ops = {
|
||||
static const struct reset_control_ops berlin_reset_ops = {
|
||||
.reset = berlin_reset_reset,
|
||||
};
|
||||
|
||||
|
@ -55,9 +55,6 @@ static int berlin_reset_xlate(struct reset_controller_dev *rcdev,
|
|||
{
|
||||
unsigned offset, bit;
|
||||
|
||||
if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
|
||||
return -EINVAL;
|
||||
|
||||
offset = reset_spec->args[0];
|
||||
bit = reset_spec->args[1];
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ static int lpc18xx_rgu_status(struct reset_controller_dev *rcdev,
|
|||
return !(readl(rc->base + offset) & bit);
|
||||
}
|
||||
|
||||
static struct reset_control_ops lpc18xx_rgu_ops = {
|
||||
static const struct reset_control_ops lpc18xx_rgu_ops = {
|
||||
.reset = lpc18xx_rgu_reset,
|
||||
.assert = lpc18xx_rgu_assert,
|
||||
.deassert = lpc18xx_rgu_deassert,
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Pistachio SoC Reset Controller driver
|
||||
*
|
||||
* Copyright (C) 2015 Imagination Technologies Ltd.
|
||||
*
|
||||
* Author: Damien Horsley <Damien.Horsley@imgtec.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
|
||||
#include <dt-bindings/reset/pistachio-resets.h>
|
||||
|
||||
#define PISTACHIO_SOFT_RESET 0
|
||||
|
||||
struct pistachio_reset_data {
|
||||
struct reset_controller_dev rcdev;
|
||||
struct regmap *periph_regs;
|
||||
};
|
||||
|
||||
static inline int pistachio_reset_shift(unsigned long id)
|
||||
{
|
||||
switch (id) {
|
||||
case PISTACHIO_RESET_I2C0:
|
||||
case PISTACHIO_RESET_I2C1:
|
||||
case PISTACHIO_RESET_I2C2:
|
||||
case PISTACHIO_RESET_I2C3:
|
||||
case PISTACHIO_RESET_I2S_IN:
|
||||
case PISTACHIO_RESET_PRL_OUT:
|
||||
case PISTACHIO_RESET_SPDIF_OUT:
|
||||
case PISTACHIO_RESET_SPI:
|
||||
case PISTACHIO_RESET_PWM_PDM:
|
||||
case PISTACHIO_RESET_UART0:
|
||||
case PISTACHIO_RESET_UART1:
|
||||
case PISTACHIO_RESET_QSPI:
|
||||
case PISTACHIO_RESET_MDC:
|
||||
case PISTACHIO_RESET_SDHOST:
|
||||
case PISTACHIO_RESET_ETHERNET:
|
||||
case PISTACHIO_RESET_IR:
|
||||
case PISTACHIO_RESET_HASH:
|
||||
case PISTACHIO_RESET_TIMER:
|
||||
return id;
|
||||
case PISTACHIO_RESET_I2S_OUT:
|
||||
case PISTACHIO_RESET_SPDIF_IN:
|
||||
case PISTACHIO_RESET_EVT:
|
||||
return id + 6;
|
||||
case PISTACHIO_RESET_USB_H:
|
||||
case PISTACHIO_RESET_USB_PR:
|
||||
case PISTACHIO_RESET_USB_PHY_PR:
|
||||
case PISTACHIO_RESET_USB_PHY_PON:
|
||||
return id + 7;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int pistachio_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct pistachio_reset_data *rd;
|
||||
u32 mask;
|
||||
int shift;
|
||||
|
||||
rd = container_of(rcdev, struct pistachio_reset_data, rcdev);
|
||||
shift = pistachio_reset_shift(id);
|
||||
if (shift < 0)
|
||||
return shift;
|
||||
mask = BIT(shift);
|
||||
|
||||
return regmap_update_bits(rd->periph_regs, PISTACHIO_SOFT_RESET,
|
||||
mask, mask);
|
||||
}
|
||||
|
||||
static int pistachio_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct pistachio_reset_data *rd;
|
||||
u32 mask;
|
||||
int shift;
|
||||
|
||||
rd = container_of(rcdev, struct pistachio_reset_data, rcdev);
|
||||
shift = pistachio_reset_shift(id);
|
||||
if (shift < 0)
|
||||
return shift;
|
||||
mask = BIT(shift);
|
||||
|
||||
return regmap_update_bits(rd->periph_regs, PISTACHIO_SOFT_RESET,
|
||||
mask, 0);
|
||||
}
|
||||
|
||||
static const struct reset_control_ops pistachio_reset_ops = {
|
||||
.assert = pistachio_reset_assert,
|
||||
.deassert = pistachio_reset_deassert,
|
||||
};
|
||||
|
||||
static int pistachio_reset_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pistachio_reset_data *rd;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
rd = devm_kzalloc(dev, sizeof(*rd), GFP_KERNEL);
|
||||
if (!rd)
|
||||
return -ENOMEM;
|
||||
|
||||
rd->periph_regs = syscon_node_to_regmap(np->parent);
|
||||
if (IS_ERR(rd->periph_regs))
|
||||
return PTR_ERR(rd->periph_regs);
|
||||
|
||||
rd->rcdev.owner = THIS_MODULE;
|
||||
rd->rcdev.nr_resets = PISTACHIO_RESET_MAX + 1;
|
||||
rd->rcdev.ops = &pistachio_reset_ops;
|
||||
rd->rcdev.of_node = np;
|
||||
|
||||
return reset_controller_register(&rd->rcdev);
|
||||
}
|
||||
|
||||
static int pistachio_reset_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pistachio_reset_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
reset_controller_unregister(&data->rcdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id pistachio_reset_dt_ids[] = {
|
||||
{ .compatible = "img,pistachio-reset", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pistachio_reset_dt_ids);
|
||||
|
||||
static struct platform_driver pistachio_reset_driver = {
|
||||
.probe = pistachio_reset_probe,
|
||||
.remove = pistachio_reset_remove,
|
||||
.driver = {
|
||||
.name = "pistachio-reset",
|
||||
.of_match_table = pistachio_reset_dt_ids,
|
||||
},
|
||||
};
|
||||
module_platform_driver(pistachio_reset_driver);
|
||||
|
||||
MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
|
||||
MODULE_DESCRIPTION("Pistacho Reset Controller Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -90,7 +90,7 @@ static int socfpga_reset_status(struct reset_controller_dev *rcdev,
|
|||
return !(reg & BIT(offset));
|
||||
}
|
||||
|
||||
static struct reset_control_ops socfpga_reset_ops = {
|
||||
static const struct reset_control_ops socfpga_reset_ops = {
|
||||
.assert = socfpga_reset_assert,
|
||||
.deassert = socfpga_reset_deassert,
|
||||
.status = socfpga_reset_status,
|
||||
|
|
|
@ -70,7 +70,7 @@ static int sunxi_reset_deassert(struct reset_controller_dev *rcdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct reset_control_ops sunxi_reset_ops = {
|
||||
static const struct reset_control_ops sunxi_reset_ops = {
|
||||
.assert = sunxi_reset_assert,
|
||||
.deassert = sunxi_reset_deassert,
|
||||
};
|
||||
|
|
|
@ -86,7 +86,7 @@ static int zynq_reset_status(struct reset_controller_dev *rcdev,
|
|||
return !!(reg & BIT(offset));
|
||||
}
|
||||
|
||||
static struct reset_control_ops zynq_reset_ops = {
|
||||
static const struct reset_control_ops zynq_reset_ops = {
|
||||
.assert = zynq_reset_assert,
|
||||
.deassert = zynq_reset_deassert,
|
||||
.status = zynq_reset_status,
|
||||
|
|
|
@ -134,7 +134,7 @@ static int syscfg_reset_status(struct reset_controller_dev *rcdev,
|
|||
return rst->active_low ? !ret_val : !!ret_val;
|
||||
}
|
||||
|
||||
static struct reset_control_ops syscfg_reset_ops = {
|
||||
static const struct reset_control_ops syscfg_reset_ops = {
|
||||
.reset = syscfg_reset_dev,
|
||||
.assert = syscfg_reset_assert,
|
||||
.deassert = syscfg_reset_deassert,
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <dt-bindings/power/rk3288-power.h>
|
||||
#include <dt-bindings/power/rk3368-power.h>
|
||||
|
||||
struct rockchip_domain_info {
|
||||
int pwr_mask;
|
||||
|
@ -75,6 +76,9 @@ struct rockchip_pmu {
|
|||
#define DOMAIN_RK3288(pwr, status, req) \
|
||||
DOMAIN(pwr, status, req, req, (req) + 16)
|
||||
|
||||
#define DOMAIN_RK3368(pwr, status, req) \
|
||||
DOMAIN(pwr, status, req, (req) + 16, req)
|
||||
|
||||
static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
|
||||
{
|
||||
struct rockchip_pmu *pmu = pd->pmu;
|
||||
|
@ -419,6 +423,7 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev)
|
|||
if (error) {
|
||||
dev_err(dev, "failed to handle node %s: %d\n",
|
||||
node->name, error);
|
||||
of_node_put(node);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
@ -444,6 +449,14 @@ static const struct rockchip_domain_info rk3288_pm_domains[] = {
|
|||
[RK3288_PD_GPU] = DOMAIN_RK3288(9, 9, 2),
|
||||
};
|
||||
|
||||
static const struct rockchip_domain_info rk3368_pm_domains[] = {
|
||||
[RK3368_PD_PERI] = DOMAIN_RK3368(13, 12, 6),
|
||||
[RK3368_PD_VIO] = DOMAIN_RK3368(15, 14, 8),
|
||||
[RK3368_PD_VIDEO] = DOMAIN_RK3368(14, 13, 7),
|
||||
[RK3368_PD_GPU_0] = DOMAIN_RK3368(16, 15, 2),
|
||||
[RK3368_PD_GPU_1] = DOMAIN_RK3368(17, 16, 2),
|
||||
};
|
||||
|
||||
static const struct rockchip_pmu_info rk3288_pmu = {
|
||||
.pwr_offset = 0x08,
|
||||
.status_offset = 0x0c,
|
||||
|
@ -461,11 +474,32 @@ static const struct rockchip_pmu_info rk3288_pmu = {
|
|||
.domain_info = rk3288_pm_domains,
|
||||
};
|
||||
|
||||
static const struct rockchip_pmu_info rk3368_pmu = {
|
||||
.pwr_offset = 0x0c,
|
||||
.status_offset = 0x10,
|
||||
.req_offset = 0x3c,
|
||||
.idle_offset = 0x40,
|
||||
.ack_offset = 0x40,
|
||||
|
||||
.core_pwrcnt_offset = 0x48,
|
||||
.gpu_pwrcnt_offset = 0x50,
|
||||
|
||||
.core_power_transition_time = 24,
|
||||
.gpu_power_transition_time = 24,
|
||||
|
||||
.num_domains = ARRAY_SIZE(rk3368_pm_domains),
|
||||
.domain_info = rk3368_pm_domains,
|
||||
};
|
||||
|
||||
static const struct of_device_id rockchip_pm_domain_dt_match[] = {
|
||||
{
|
||||
.compatible = "rockchip,rk3288-power-controller",
|
||||
.data = (void *)&rk3288_pmu,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3368-power-controller",
|
||||
.data = (void *)&rk3368_pmu,
|
||||
},
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ static int sunxi_sram_show(struct seq_file *s, void *data)
|
|||
|
||||
val = readl(base + sram_data->reg);
|
||||
val >>= sram_data->offset;
|
||||
val &= sram_data->width;
|
||||
val &= GENMASK(sram_data->width - 1, 0);
|
||||
|
||||
for (func = sram_data->func; func->func; func++) {
|
||||
seq_printf(s, "\t\t%s%c\n", func->func,
|
||||
|
@ -208,7 +208,8 @@ int sunxi_sram_claim(struct device *dev)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
mask = GENMASK(sram_data->offset + sram_data->width, sram_data->offset);
|
||||
mask = GENMASK(sram_data->offset + sram_data->width - 1,
|
||||
sram_data->offset);
|
||||
val = readl(base + sram_data->reg);
|
||||
val &= ~mask;
|
||||
writel(val | ((device << sram_data->offset) & mask),
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/atmel_usba_udc.h>
|
||||
|
@ -1886,20 +1888,15 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
|
|||
#ifdef CONFIG_OF
|
||||
static void at91sam9rl_toggle_bias(struct usba_udc *udc, int is_on)
|
||||
{
|
||||
unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
|
||||
|
||||
if (is_on)
|
||||
at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
|
||||
else
|
||||
at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
|
||||
regmap_update_bits(udc->pmc, AT91_CKGR_UCKR, AT91_PMC_BIASEN,
|
||||
is_on ? AT91_PMC_BIASEN : 0);
|
||||
}
|
||||
|
||||
static void at91sam9g45_pulse_bias(struct usba_udc *udc)
|
||||
{
|
||||
unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
|
||||
|
||||
at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
|
||||
at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
|
||||
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_BIASEN);
|
||||
}
|
||||
|
||||
static const struct usba_udc_errata at91sam9rl_errata = {
|
||||
|
@ -1936,6 +1933,9 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
|
|||
return ERR_PTR(-EINVAL);
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -354,6 +354,8 @@ struct usba_udc {
|
|||
struct dentry *debugfs_root;
|
||||
struct dentry *debugfs_regs;
|
||||
#endif
|
||||
|
||||
struct regmap *pmc;
|
||||
};
|
||||
|
||||
static inline struct usba_ep *to_usba_ep(struct usb_ep *ep)
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef __DT_BINDINGS_POWER_RK3368_POWER_H__
|
||||
#define __DT_BINDINGS_POWER_RK3368_POWER_H__
|
||||
|
||||
/* VD_CORE */
|
||||
#define RK3368_PD_A53_L0 0
|
||||
#define RK3368_PD_A53_L1 1
|
||||
#define RK3368_PD_A53_L2 2
|
||||
#define RK3368_PD_A53_L3 3
|
||||
#define RK3368_PD_SCU_L 4
|
||||
#define RK3368_PD_A53_B0 5
|
||||
#define RK3368_PD_A53_B1 6
|
||||
#define RK3368_PD_A53_B2 7
|
||||
#define RK3368_PD_A53_B3 8
|
||||
#define RK3368_PD_SCU_B 9
|
||||
|
||||
/* VD_LOGIC */
|
||||
#define RK3368_PD_BUS 10
|
||||
#define RK3368_PD_PERI 11
|
||||
#define RK3368_PD_VIO 12
|
||||
#define RK3368_PD_ALIVE 13
|
||||
#define RK3368_PD_VIDEO 14
|
||||
#define RK3368_PD_GPU_0 15
|
||||
#define RK3368_PD_GPU_1 16
|
||||
|
||||
/* VD_PMU */
|
||||
#define RK3368_PD_PMU 17
|
||||
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* This header provides constants for the reset controller
|
||||
* present in the Pistachio SoC
|
||||
*/
|
||||
|
||||
#ifndef _PISTACHIO_RESETS_H
|
||||
#define _PISTACHIO_RESETS_H
|
||||
|
||||
#define PISTACHIO_RESET_I2C0 0
|
||||
#define PISTACHIO_RESET_I2C1 1
|
||||
#define PISTACHIO_RESET_I2C2 2
|
||||
#define PISTACHIO_RESET_I2C3 3
|
||||
#define PISTACHIO_RESET_I2S_IN 4
|
||||
#define PISTACHIO_RESET_PRL_OUT 5
|
||||
#define PISTACHIO_RESET_SPDIF_OUT 6
|
||||
#define PISTACHIO_RESET_SPI 7
|
||||
#define PISTACHIO_RESET_PWM_PDM 8
|
||||
#define PISTACHIO_RESET_UART0 9
|
||||
#define PISTACHIO_RESET_UART1 10
|
||||
#define PISTACHIO_RESET_QSPI 11
|
||||
#define PISTACHIO_RESET_MDC 12
|
||||
#define PISTACHIO_RESET_SDHOST 13
|
||||
#define PISTACHIO_RESET_ETHERNET 14
|
||||
#define PISTACHIO_RESET_IR 15
|
||||
#define PISTACHIO_RESET_HASH 16
|
||||
#define PISTACHIO_RESET_TIMER 17
|
||||
#define PISTACHIO_RESET_I2S_OUT 18
|
||||
#define PISTACHIO_RESET_SPDIF_IN 19
|
||||
#define PISTACHIO_RESET_EVT 20
|
||||
#define PISTACHIO_RESET_USB_H 21
|
||||
#define PISTACHIO_RESET_USB_PR 22
|
||||
#define PISTACHIO_RESET_USB_PHY_PR 23
|
||||
#define PISTACHIO_RESET_USB_PHY_PON 24
|
||||
#define PISTACHIO_RESET_MAX 24
|
||||
|
||||
#endif
|
|
@ -16,18 +16,6 @@
|
|||
#ifndef 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_SCDR 0x04 /* System Clock Disable Register */
|
||||
|
||||
|
|
|
@ -51,6 +51,9 @@ struct gpmc_timings {
|
|||
u32 adv_on; /* Assertion time */
|
||||
u32 adv_rd_off; /* Read deassertion time */
|
||||
u32 adv_wr_off; /* Write deassertion time */
|
||||
u32 adv_aad_mux_on; /* ADV assertion time for AAD */
|
||||
u32 adv_aad_mux_rd_off; /* ADV read deassertion time for AAD */
|
||||
u32 adv_aad_mux_wr_off; /* ADV write deassertion time for AAD */
|
||||
|
||||
/* WE signals timings corresponding to GPMC_CONFIG4 */
|
||||
u32 we_on; /* WE assertion time */
|
||||
|
@ -59,6 +62,8 @@ struct gpmc_timings {
|
|||
/* OE signals timings corresponding to GPMC_CONFIG4 */
|
||||
u32 oe_on; /* OE assertion time */
|
||||
u32 oe_off; /* OE deassertion time */
|
||||
u32 oe_aad_mux_on; /* OE assertion time for AAD */
|
||||
u32 oe_aad_mux_off; /* OE deassertion time for AAD */
|
||||
|
||||
/* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
|
||||
u32 page_burst_access; /* Multiple access word delay */
|
||||
|
|
|
@ -38,7 +38,7 @@ struct of_phandle_args;
|
|||
* @nr_resets: number of reset controls in this reset controller device
|
||||
*/
|
||||
struct reset_controller_dev {
|
||||
struct reset_control_ops *ops;
|
||||
const struct reset_control_ops *ops;
|
||||
struct module *owner;
|
||||
struct list_head list;
|
||||
struct device_node *of_node;
|
||||
|
|
|
@ -33,6 +33,7 @@ enum scpi_sensor_class {
|
|||
VOLTAGE,
|
||||
CURRENT,
|
||||
POWER,
|
||||
ENERGY,
|
||||
};
|
||||
|
||||
struct scpi_sensor_info {
|
||||
|
@ -68,7 +69,7 @@ struct scpi_ops {
|
|||
struct scpi_dvfs_info *(*dvfs_get_info)(u8);
|
||||
int (*sensor_get_capability)(u16 *sensors);
|
||||
int (*sensor_get_info)(u16 sensor_id, struct scpi_sensor_info *);
|
||||
int (*sensor_get_value)(u16, u32 *);
|
||||
int (*sensor_get_value)(u16, u64 *);
|
||||
};
|
||||
|
||||
#if IS_REACHABLE(CONFIG_ARM_SCPI_PROTOCOL)
|
||||
|
|
Loading…
Reference in New Issue