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:
Linus Torvalds 2016-03-20 15:40:32 -07:00
commit 46e595a17d
51 changed files with 1136 additions and 1329 deletions

View File

@ -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:

View File

@ -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

View File

@ -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>;
/* ... */
};

View File

@ -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

View File

@ -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();
}

View File

@ -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)

View File

@ -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 */

View File

@ -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);
}

View File

@ -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 = {

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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_ */

View File

@ -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 = {

View File

@ -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);

View File

@ -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;
}

View File

@ -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",

View File

@ -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/

View File

@ -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);

View File

@ -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[] = {

View File

@ -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,

View File

@ -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];

View File

@ -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,

View File

@ -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");

View File

@ -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,

View File

@ -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,
};

View File

@ -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,

View File

@ -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,

View File

@ -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 */ },
};

View File

@ -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),

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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;

View File

@ -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)