Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux

Pull clk updates from Stephen Boyd:
 "This time it looks like a quieter release cycle in the clk tree. I
  guess that's because of summer time holidays/vacations. The biggest
  change in the diffstat is in the Qualcomm clk driver, where they got
  support for CPUs and handful of SoCs. After that, the at91 driver got
  a major rewrite for newer DT bindings that should make things easier
  going forward and the TI code moved to a clockdomain based design.

  The long tail is mostly small driver updates for newer clks and some
  simpler SoC clock drivers such as the Hisilicon and imx support.

  In the core framework, we only have two small changes this time.

  One is a new clk API to get all clks for a device with the bulk clk
  APIs. This allows drivers that don't care about doing anything besides
  turning on all the clks to just clk_get() them all and turn them on.

  The other change is the beginning of a way to support save and restore
  of clk settings in the clk framework. TI is the only user right now,
  but we will want to expand upon this design in the future to support
  more save and restore of clk registers. At least this gets us started
  and works well enough for one SoC, but there's more work in the
  future.

  Core:
   - clk_bulk_get_all() API and friends to get all the clks for a device
   - Basic clk state save/restore hooks

  New Drivers:
   - Renesas RZ/A2 (R7S9210) SoC, including early clocks
   - Rensas RZ/G1N (R8A7744) and RZ/G2E (R8A774C0) SoCs
   - Rensas RZ/G2M (r8a774a1) SoC
   - Qualcomm Krait CPU clk support
   - Qualcomm QCS404 GCC support
   - Qualcomm SDM660 GCC support
   - Qualcomm SDM845 camera clock controller
   - Ingenic jz4725b CGU
   - Hisilicon 3670 SoC support
   - TI SCI clks on K3 SoCs
   - iMX6 MMDC clks
   - Reset Controller (RMU) support for Actions Semi Owl S900 and S700 SoCs

  Updates:
   - Rework at91 PMC clock driver for new DT bindings
   - Nvidia Tegra clk driver MBIST workaround fix
   - S2RAM support for Marvell mvebu periph clks
   - Use updated printk format for OF node names
   - Fix TI code to only search DT subnodes
   - Various static analysis finds
   - Tag various drivers with SPDX license tags
   - Support dynamic frequency switching (DFS) on qcom SDM845 GCC
   - Only use s2mps11 dt-binding defines instead of redefining them in the driver
   - Add some more missing clks to qcom MSM8996 GCC
   - Quad SPI clks on qcom SDM845
   - Add support for CMT timer clocks on R-Car V3H
   - Add support for SHDI and various timer clocks on R-Car V3M
   - Improve OSC and RCLK (watchdog) handling on R-Car Gen3 SoCs
   - Amlogic clk-pll driver improvements and updates
   - Amlogic axg audio controller system clocks
   - Register Amlogic meson8b clock controller early
   - Add support for SATA and Fine Display Processor (FDP) clocks on R-Car M3-N
   - Consolidation of system suspend related code in Exynos, S5P, S3C SoC clk drivers
   - Fixes for system suspend support on Exynos542x (Odroid boards) and Exynos5433 SoC
   - Remove obsoleted Exynos4212 ISP clock definitions
   - Migrated TI am3/4/5 and dra7 SoCs to clockdomain based design
   - TI RTC+DDR sleep mode support for clock save/restore
   - Allwinner A64 display engine support and fixes
   - Allwinner A83t display engine support and fixes"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (186 commits)
  clk: qcom: Remove unused arrays in SDM845 GCC
  clk: fixed-rate: fix of_node_get-put imbalance
  clk: s2mps11: Add used attribute to s2mps11_dt_match
  clk: qcom: gcc-sdm660: Add MODULE_LICENSE
  clk: qcom: Add safe switch hook for krait mux clocks
  dt-bindings: clock: Document qcom,krait-cc
  clk: qcom: Add Krait clock controller driver
  dt-bindings: arm: Document qcom,kpss-gcc
  clk: qcom: Add KPSS ACC/GCC driver
  clk: qcom: Add support for Krait clocks
  clk: qcom: Add IPQ806X's HFPLLs
  clk: qcom: Add MSM8960/APQ8064's HFPLLs
  dt-bindings: clock: Document qcom,hfpll
  clk: qcom: Add HFPLL driver
  clk: qcom: Add support for High-Frequency PLLs (HFPLLs)
  ARM: Add Krait L2 register accessor functions
  clk: imx6q: add mmdc0 ipg clock
  clk: imx6sl: add mmdc ipg clocks
  clk: imx6sll: add mmdc1 ipg clock
  clk: imx6sx: add mmdc1 ipg clock
  ...
This commit is contained in:
Linus Torvalds
2018-10-31 11:08:30 -07:00
284 changed files with 20513 additions and 4254 deletions

View File

@@ -287,6 +287,7 @@ source "drivers/clk/actions/Kconfig"
source "drivers/clk/bcm/Kconfig"
source "drivers/clk/hisilicon/Kconfig"
source "drivers/clk/imgtec/Kconfig"
source "drivers/clk/ingenic/Kconfig"
source "drivers/clk/keystone/Kconfig"
source "drivers/clk/mediatek/Kconfig"
source "drivers/clk/meson/Kconfig"

View File

@@ -72,7 +72,8 @@ obj-$(CONFIG_H8300) += h8300/
obj-$(CONFIG_ARCH_HISI) += hisilicon/
obj-y += imgtec/
obj-$(CONFIG_ARCH_MXC) += imx/
obj-$(CONFIG_MACH_INGENIC) += ingenic/
obj-y += ingenic/
obj-$(CONFIG_ARCH_K3) += keystone/
obj-$(CONFIG_ARCH_KEYSTONE) += keystone/
obj-$(CONFIG_MACH_LOONGSON32) += loongson1/
obj-y += mediatek/

View File

@@ -2,6 +2,7 @@ config CLK_ACTIONS
bool "Clock driver for Actions Semi SoCs"
depends on ARCH_ACTIONS || COMPILE_TEST
select REGMAP_MMIO
select RESET_CONTROLLER
default ARCH_ACTIONS
if CLK_ACTIONS

View File

@@ -7,6 +7,7 @@ clk-owl-y += owl-divider.o
clk-owl-y += owl-factor.o
clk-owl-y += owl-composite.o
clk-owl-y += owl-pll.o
clk-owl-y += owl-reset.o
# SoC support
obj-$(CONFIG_CLK_OWL_S700) += owl-s700.o

View File

@@ -39,7 +39,7 @@ static void owl_clk_set_regmap(const struct owl_clk_desc *desc,
}
int owl_clk_regmap_init(struct platform_device *pdev,
const struct owl_clk_desc *desc)
struct owl_clk_desc *desc)
{
void __iomem *base;
struct regmap *regmap;
@@ -57,6 +57,7 @@ int owl_clk_regmap_init(struct platform_device *pdev,
}
owl_clk_set_regmap(desc, regmap);
desc->regmap = regmap;
return 0;
}

View File

@@ -26,6 +26,9 @@ struct owl_clk_desc {
struct owl_clk_common **clks;
unsigned long num_clks;
struct clk_hw_onecell_data *hw_clks;
const struct owl_reset_map *resets;
unsigned long num_resets;
struct regmap *regmap;
};
static inline struct owl_clk_common *
@@ -35,7 +38,7 @@ static inline struct owl_clk_common *
}
int owl_clk_regmap_init(struct platform_device *pdev,
const struct owl_clk_desc *desc);
struct owl_clk_desc *desc);
int owl_clk_probe(struct device *dev, struct clk_hw_onecell_data *hw_clks);
#endif /* _OWL_COMMON_H_ */

View File

@@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-2.0-or-later
//
// Actions Semi Owl SoCs Reset Management Unit driver
//
// Copyright (c) 2018 Linaro Ltd.
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/reset-controller.h>
#include "owl-reset.h"
static int owl_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct owl_reset *reset = to_owl_reset(rcdev);
const struct owl_reset_map *map = &reset->reset_map[id];
return regmap_update_bits(reset->regmap, map->reg, map->bit, 0);
}
static int owl_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct owl_reset *reset = to_owl_reset(rcdev);
const struct owl_reset_map *map = &reset->reset_map[id];
return regmap_update_bits(reset->regmap, map->reg, map->bit, map->bit);
}
static int owl_reset_reset(struct reset_controller_dev *rcdev,
unsigned long id)
{
owl_reset_assert(rcdev, id);
udelay(1);
owl_reset_deassert(rcdev, id);
return 0;
}
static int owl_reset_status(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct owl_reset *reset = to_owl_reset(rcdev);
const struct owl_reset_map *map = &reset->reset_map[id];
u32 reg;
int ret;
ret = regmap_read(reset->regmap, map->reg, &reg);
if (ret)
return ret;
/*
* The reset control API expects 0 if reset is not asserted,
* which is the opposite of what our hardware uses.
*/
return !(map->bit & reg);
}
const struct reset_control_ops owl_reset_ops = {
.assert = owl_reset_assert,
.deassert = owl_reset_deassert,
.reset = owl_reset_reset,
.status = owl_reset_status,
};

View File

@@ -0,0 +1,31 @@
// SPDX-License-Identifier: GPL-2.0-or-later
//
// Actions Semi Owl SoCs Reset Management Unit driver
//
// Copyright (c) 2018 Linaro Ltd.
// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
#ifndef _OWL_RESET_H_
#define _OWL_RESET_H_
#include <linux/reset-controller.h>
struct owl_reset_map {
u32 reg;
u32 bit;
};
struct owl_reset {
struct reset_controller_dev rcdev;
const struct owl_reset_map *reset_map;
struct regmap *regmap;
};
static inline struct owl_reset *to_owl_reset(struct reset_controller_dev *rcdev)
{
return container_of(rcdev, struct owl_reset, rcdev);
}
extern const struct reset_control_ops owl_reset_ops;
#endif /* _OWL_RESET_H_ */

View File

@@ -20,8 +20,10 @@
#include "owl-gate.h"
#include "owl-mux.h"
#include "owl-pll.h"
#include "owl-reset.h"
#include <dt-bindings/clock/actions,s700-cmu.h>
#include <dt-bindings/reset/actions,s700-reset.h>
#define CMU_COREPLL (0x0000)
#define CMU_DEVPLL (0x0004)
@@ -569,20 +571,69 @@ static struct clk_hw_onecell_data s700_hw_clks = {
.num = CLK_NR_CLKS,
};
static const struct owl_clk_desc s700_clk_desc = {
static const struct owl_reset_map s700_resets[] = {
[RESET_DE] = { CMU_DEVRST0, BIT(0) },
[RESET_LCD0] = { CMU_DEVRST0, BIT(1) },
[RESET_DSI] = { CMU_DEVRST0, BIT(2) },
[RESET_CSI] = { CMU_DEVRST0, BIT(13) },
[RESET_SI] = { CMU_DEVRST0, BIT(14) },
[RESET_I2C0] = { CMU_DEVRST1, BIT(0) },
[RESET_I2C1] = { CMU_DEVRST1, BIT(1) },
[RESET_I2C2] = { CMU_DEVRST1, BIT(2) },
[RESET_I2C3] = { CMU_DEVRST1, BIT(3) },
[RESET_SPI0] = { CMU_DEVRST1, BIT(4) },
[RESET_SPI1] = { CMU_DEVRST1, BIT(5) },
[RESET_SPI2] = { CMU_DEVRST1, BIT(6) },
[RESET_SPI3] = { CMU_DEVRST1, BIT(7) },
[RESET_UART0] = { CMU_DEVRST1, BIT(8) },
[RESET_UART1] = { CMU_DEVRST1, BIT(9) },
[RESET_UART2] = { CMU_DEVRST1, BIT(10) },
[RESET_UART3] = { CMU_DEVRST1, BIT(11) },
[RESET_UART4] = { CMU_DEVRST1, BIT(12) },
[RESET_UART5] = { CMU_DEVRST1, BIT(13) },
[RESET_UART6] = { CMU_DEVRST1, BIT(14) },
[RESET_KEY] = { CMU_DEVRST1, BIT(24) },
[RESET_GPIO] = { CMU_DEVRST1, BIT(25) },
[RESET_AUDIO] = { CMU_DEVRST1, BIT(29) },
};
static struct owl_clk_desc s700_clk_desc = {
.clks = s700_clks,
.num_clks = ARRAY_SIZE(s700_clks),
.hw_clks = &s700_hw_clks,
.resets = s700_resets,
.num_resets = ARRAY_SIZE(s700_resets),
};
static int s700_clk_probe(struct platform_device *pdev)
{
const struct owl_clk_desc *desc;
struct owl_clk_desc *desc;
struct owl_reset *reset;
int ret;
desc = &s700_clk_desc;
owl_clk_regmap_init(pdev, desc);
/*
* FIXME: Reset controller registration should be moved to
* common code, once all SoCs of Owl family supports it.
*/
reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
if (!reset)
return -ENOMEM;
reset->rcdev.of_node = pdev->dev.of_node;
reset->rcdev.ops = &owl_reset_ops;
reset->rcdev.nr_resets = desc->num_resets;
reset->reset_map = desc->resets;
reset->regmap = desc->regmap;
ret = devm_reset_controller_register(&pdev->dev, &reset->rcdev);
if (ret)
dev_err(&pdev->dev, "Failed to register reset controller\n");
return owl_clk_probe(&pdev->dev, desc->hw_clks);
}

View File

@@ -19,8 +19,10 @@
#include "owl-gate.h"
#include "owl-mux.h"
#include "owl-pll.h"
#include "owl-reset.h"
#include <dt-bindings/clock/actions,s900-cmu.h>
#include <dt-bindings/reset/actions,s900-reset.h>
#define CMU_COREPLL (0x0000)
#define CMU_DEVPLL (0x0004)
@@ -684,20 +686,100 @@ static struct clk_hw_onecell_data s900_hw_clks = {
.num = CLK_NR_CLKS,
};
static const struct owl_clk_desc s900_clk_desc = {
static const struct owl_reset_map s900_resets[] = {
[RESET_DMAC] = { CMU_DEVRST0, BIT(0) },
[RESET_SRAMI] = { CMU_DEVRST0, BIT(1) },
[RESET_DDR_CTL_PHY] = { CMU_DEVRST0, BIT(2) },
[RESET_NANDC0] = { CMU_DEVRST0, BIT(3) },
[RESET_SD0] = { CMU_DEVRST0, BIT(4) },
[RESET_SD1] = { CMU_DEVRST0, BIT(5) },
[RESET_PCM1] = { CMU_DEVRST0, BIT(6) },
[RESET_DE] = { CMU_DEVRST0, BIT(7) },
[RESET_LVDS] = { CMU_DEVRST0, BIT(8) },
[RESET_SD2] = { CMU_DEVRST0, BIT(9) },
[RESET_DSI] = { CMU_DEVRST0, BIT(10) },
[RESET_CSI0] = { CMU_DEVRST0, BIT(11) },
[RESET_BISP_AXI] = { CMU_DEVRST0, BIT(12) },
[RESET_CSI1] = { CMU_DEVRST0, BIT(13) },
[RESET_GPIO] = { CMU_DEVRST0, BIT(15) },
[RESET_EDP] = { CMU_DEVRST0, BIT(16) },
[RESET_AUDIO] = { CMU_DEVRST0, BIT(17) },
[RESET_PCM0] = { CMU_DEVRST0, BIT(18) },
[RESET_HDE] = { CMU_DEVRST0, BIT(21) },
[RESET_GPU3D_PA] = { CMU_DEVRST0, BIT(22) },
[RESET_IMX] = { CMU_DEVRST0, BIT(23) },
[RESET_SE] = { CMU_DEVRST0, BIT(24) },
[RESET_NANDC1] = { CMU_DEVRST0, BIT(25) },
[RESET_SD3] = { CMU_DEVRST0, BIT(26) },
[RESET_GIC] = { CMU_DEVRST0, BIT(27) },
[RESET_GPU3D_PB] = { CMU_DEVRST0, BIT(28) },
[RESET_DDR_CTL_PHY_AXI] = { CMU_DEVRST0, BIT(29) },
[RESET_CMU_DDR] = { CMU_DEVRST0, BIT(30) },
[RESET_DMM] = { CMU_DEVRST0, BIT(31) },
[RESET_USB2HUB] = { CMU_DEVRST1, BIT(0) },
[RESET_USB2HSIC] = { CMU_DEVRST1, BIT(1) },
[RESET_HDMI] = { CMU_DEVRST1, BIT(2) },
[RESET_HDCP2TX] = { CMU_DEVRST1, BIT(3) },
[RESET_UART6] = { CMU_DEVRST1, BIT(4) },
[RESET_UART0] = { CMU_DEVRST1, BIT(5) },
[RESET_UART1] = { CMU_DEVRST1, BIT(6) },
[RESET_UART2] = { CMU_DEVRST1, BIT(7) },
[RESET_SPI0] = { CMU_DEVRST1, BIT(8) },
[RESET_SPI1] = { CMU_DEVRST1, BIT(9) },
[RESET_SPI2] = { CMU_DEVRST1, BIT(10) },
[RESET_SPI3] = { CMU_DEVRST1, BIT(11) },
[RESET_I2C0] = { CMU_DEVRST1, BIT(12) },
[RESET_I2C1] = { CMU_DEVRST1, BIT(13) },
[RESET_USB3] = { CMU_DEVRST1, BIT(14) },
[RESET_UART3] = { CMU_DEVRST1, BIT(15) },
[RESET_UART4] = { CMU_DEVRST1, BIT(16) },
[RESET_UART5] = { CMU_DEVRST1, BIT(17) },
[RESET_I2C2] = { CMU_DEVRST1, BIT(18) },
[RESET_I2C3] = { CMU_DEVRST1, BIT(19) },
[RESET_ETHERNET] = { CMU_DEVRST1, BIT(20) },
[RESET_CHIPID] = { CMU_DEVRST1, BIT(21) },
[RESET_I2C4] = { CMU_DEVRST1, BIT(22) },
[RESET_I2C5] = { CMU_DEVRST1, BIT(23) },
[RESET_CPU_SCNT] = { CMU_DEVRST1, BIT(30) }
};
static struct owl_clk_desc s900_clk_desc = {
.clks = s900_clks,
.num_clks = ARRAY_SIZE(s900_clks),
.hw_clks = &s900_hw_clks,
.resets = s900_resets,
.num_resets = ARRAY_SIZE(s900_resets),
};
static int s900_clk_probe(struct platform_device *pdev)
{
const struct owl_clk_desc *desc;
struct owl_clk_desc *desc;
struct owl_reset *reset;
int ret;
desc = &s900_clk_desc;
owl_clk_regmap_init(pdev, desc);
/*
* FIXME: Reset controller registration should be moved to
* common code, once all SoCs of Owl family supports it.
*/
reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
if (!reset)
return -ENOMEM;
reset->rcdev.of_node = pdev->dev.of_node;
reset->rcdev.ops = &owl_reset_ops;
reset->rcdev.nr_resets = desc->num_resets;
reset->reset_map = desc->resets;
reset->regmap = desc->regmap;
ret = devm_reset_controller_register(&pdev->dev, &reset->rcdev);
if (ret)
dev_err(&pdev->dev, "Failed to register reset controller\n");
return owl_clk_probe(&pdev->dev, desc->hw_clks);
}

View File

@@ -3,7 +3,7 @@
# Makefile for at91 specific clk
#
obj-y += pmc.o sckc.o
obj-y += pmc.o sckc.o dt-compat.o
obj-y += clk-slow.o clk-main.o clk-pll.o clk-plldiv.o clk-master.o
obj-y += clk-system.o clk-peripheral.o clk-programmable.o
@@ -14,3 +14,6 @@ obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o
obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o
obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o
obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o
obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o
obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o
obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o

View File

@@ -0,0 +1,494 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
#include <dt-bindings/clock/at91.h>
#include "pmc.h"
struct sck {
char *n;
char *p;
u8 id;
};
struct pck {
char *n;
u8 id;
};
struct at91sam926x_data {
const struct clk_pll_layout *plla_layout;
const struct clk_pll_characteristics *plla_characteristics;
const struct clk_pll_layout *pllb_layout;
const struct clk_pll_characteristics *pllb_characteristics;
const struct clk_master_characteristics *mck_characteristics;
const struct sck *sck;
const struct pck *pck;
u8 num_sck;
u8 num_pck;
u8 num_progck;
bool has_slck;
};
static const struct clk_master_characteristics sam9260_mck_characteristics = {
.output = { .min = 0, .max = 105000000 },
.divisors = { 1, 2, 4, 0 },
};
static u8 sam9260_plla_out[] = { 0, 2 };
static u16 sam9260_plla_icpll[] = { 1, 1 };
static struct clk_range sam9260_plla_outputs[] = {
{ .min = 80000000, .max = 160000000 },
{ .min = 150000000, .max = 240000000 },
};
static const struct clk_pll_characteristics sam9260_plla_characteristics = {
.input = { .min = 1000000, .max = 32000000 },
.num_output = ARRAY_SIZE(sam9260_plla_outputs),
.output = sam9260_plla_outputs,
.icpll = sam9260_plla_icpll,
.out = sam9260_plla_out,
};
static u8 sam9260_pllb_out[] = { 1 };
static u16 sam9260_pllb_icpll[] = { 1 };
static struct clk_range sam9260_pllb_outputs[] = {
{ .min = 70000000, .max = 130000000 },
};
static const struct clk_pll_characteristics sam9260_pllb_characteristics = {
.input = { .min = 1000000, .max = 5000000 },
.num_output = ARRAY_SIZE(sam9260_pllb_outputs),
.output = sam9260_pllb_outputs,
.icpll = sam9260_pllb_icpll,
.out = sam9260_pllb_out,
};
static const struct sck at91sam9260_systemck[] = {
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "udpck", .p = "usbck", .id = 7 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
};
static const struct pck at91sam9260_periphck[] = {
{ .n = "pioA_clk", .id = 2 },
{ .n = "pioB_clk", .id = 3 },
{ .n = "pioC_clk", .id = 4 },
{ .n = "adc_clk", .id = 5 },
{ .n = "usart0_clk", .id = 6 },
{ .n = "usart1_clk", .id = 7 },
{ .n = "usart2_clk", .id = 8 },
{ .n = "mci0_clk", .id = 9 },
{ .n = "udc_clk", .id = 10 },
{ .n = "twi0_clk", .id = 11 },
{ .n = "spi0_clk", .id = 12 },
{ .n = "spi1_clk", .id = 13 },
{ .n = "ssc0_clk", .id = 14 },
{ .n = "tc0_clk", .id = 17 },
{ .n = "tc1_clk", .id = 18 },
{ .n = "tc2_clk", .id = 19 },
{ .n = "ohci_clk", .id = 20 },
{ .n = "macb0_clk", .id = 21 },
{ .n = "isi_clk", .id = 22 },
{ .n = "usart3_clk", .id = 23 },
{ .n = "uart0_clk", .id = 24 },
{ .n = "uart1_clk", .id = 25 },
{ .n = "tc3_clk", .id = 26 },
{ .n = "tc4_clk", .id = 27 },
{ .n = "tc5_clk", .id = 28 },
};
static struct at91sam926x_data at91sam9260_data = {
.plla_layout = &at91rm9200_pll_layout,
.plla_characteristics = &sam9260_plla_characteristics,
.pllb_layout = &at91rm9200_pll_layout,
.pllb_characteristics = &sam9260_pllb_characteristics,
.mck_characteristics = &sam9260_mck_characteristics,
.sck = at91sam9260_systemck,
.num_sck = ARRAY_SIZE(at91sam9260_systemck),
.pck = at91sam9260_periphck,
.num_pck = ARRAY_SIZE(at91sam9260_periphck),
.num_progck = 2,
.has_slck = true,
};
static const struct clk_master_characteristics sam9g20_mck_characteristics = {
.output = { .min = 0, .max = 133000000 },
.divisors = { 1, 2, 4, 6 },
};
static u8 sam9g20_plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 };
static u16 sam9g20_plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 };
static struct clk_range sam9g20_plla_outputs[] = {
{ .min = 745000000, .max = 800000000 },
{ .min = 695000000, .max = 750000000 },
{ .min = 645000000, .max = 700000000 },
{ .min = 595000000, .max = 650000000 },
{ .min = 545000000, .max = 600000000 },
{ .min = 495000000, .max = 550000000 },
{ .min = 445000000, .max = 500000000 },
{ .min = 400000000, .max = 450000000 },
};
static const struct clk_pll_characteristics sam9g20_plla_characteristics = {
.input = { .min = 2000000, .max = 32000000 },
.num_output = ARRAY_SIZE(sam9g20_plla_outputs),
.output = sam9g20_plla_outputs,
.icpll = sam9g20_plla_icpll,
.out = sam9g20_plla_out,
};
static u8 sam9g20_pllb_out[] = { 0 };
static u16 sam9g20_pllb_icpll[] = { 0 };
static struct clk_range sam9g20_pllb_outputs[] = {
{ .min = 30000000, .max = 100000000 },
};
static const struct clk_pll_characteristics sam9g20_pllb_characteristics = {
.input = { .min = 2000000, .max = 32000000 },
.num_output = ARRAY_SIZE(sam9g20_pllb_outputs),
.output = sam9g20_pllb_outputs,
.icpll = sam9g20_pllb_icpll,
.out = sam9g20_pllb_out,
};
static struct at91sam926x_data at91sam9g20_data = {
.plla_layout = &at91sam9g45_pll_layout,
.plla_characteristics = &sam9g20_plla_characteristics,
.pllb_layout = &at91sam9g20_pllb_layout,
.pllb_characteristics = &sam9g20_pllb_characteristics,
.mck_characteristics = &sam9g20_mck_characteristics,
.sck = at91sam9260_systemck,
.num_sck = ARRAY_SIZE(at91sam9260_systemck),
.pck = at91sam9260_periphck,
.num_pck = ARRAY_SIZE(at91sam9260_periphck),
.num_progck = 2,
.has_slck = true,
};
static const struct clk_master_characteristics sam9261_mck_characteristics = {
.output = { .min = 0, .max = 94000000 },
.divisors = { 1, 2, 4, 0 },
};
static struct clk_range sam9261_plla_outputs[] = {
{ .min = 80000000, .max = 200000000 },
{ .min = 190000000, .max = 240000000 },
};
static const struct clk_pll_characteristics sam9261_plla_characteristics = {
.input = { .min = 1000000, .max = 32000000 },
.num_output = ARRAY_SIZE(sam9261_plla_outputs),
.output = sam9261_plla_outputs,
.icpll = sam9260_plla_icpll,
.out = sam9260_plla_out,
};
static u8 sam9261_pllb_out[] = { 1 };
static u16 sam9261_pllb_icpll[] = { 1 };
static struct clk_range sam9261_pllb_outputs[] = {
{ .min = 70000000, .max = 130000000 },
};
static const struct clk_pll_characteristics sam9261_pllb_characteristics = {
.input = { .min = 1000000, .max = 5000000 },
.num_output = ARRAY_SIZE(sam9261_pllb_outputs),
.output = sam9261_pllb_outputs,
.icpll = sam9261_pllb_icpll,
.out = sam9261_pllb_out,
};
static const struct sck at91sam9261_systemck[] = {
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "udpck", .p = "usbck", .id = 7 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
{ .n = "pck2", .p = "prog2", .id = 10 },
{ .n = "pck3", .p = "prog3", .id = 11 },
{ .n = "hclk0", .p = "masterck", .id = 16 },
{ .n = "hclk1", .p = "masterck", .id = 17 },
};
static const struct pck at91sam9261_periphck[] = {
{ .n = "pioA_clk", .id = 2, },
{ .n = "pioB_clk", .id = 3, },
{ .n = "pioC_clk", .id = 4, },
{ .n = "usart0_clk", .id = 6, },
{ .n = "usart1_clk", .id = 7, },
{ .n = "usart2_clk", .id = 8, },
{ .n = "mci0_clk", .id = 9, },
{ .n = "udc_clk", .id = 10, },
{ .n = "twi0_clk", .id = 11, },
{ .n = "spi0_clk", .id = 12, },
{ .n = "spi1_clk", .id = 13, },
{ .n = "ssc0_clk", .id = 14, },
{ .n = "ssc1_clk", .id = 15, },
{ .n = "ssc2_clk", .id = 16, },
{ .n = "tc0_clk", .id = 17, },
{ .n = "tc1_clk", .id = 18, },
{ .n = "tc2_clk", .id = 19, },
{ .n = "ohci_clk", .id = 20, },
{ .n = "lcd_clk", .id = 21, },
};
static struct at91sam926x_data at91sam9261_data = {
.plla_layout = &at91rm9200_pll_layout,
.plla_characteristics = &sam9261_plla_characteristics,
.pllb_layout = &at91rm9200_pll_layout,
.pllb_characteristics = &sam9261_pllb_characteristics,
.mck_characteristics = &sam9261_mck_characteristics,
.sck = at91sam9261_systemck,
.num_sck = ARRAY_SIZE(at91sam9261_systemck),
.pck = at91sam9261_periphck,
.num_pck = ARRAY_SIZE(at91sam9261_periphck),
.num_progck = 4,
};
static const struct clk_master_characteristics sam9263_mck_characteristics = {
.output = { .min = 0, .max = 120000000 },
.divisors = { 1, 2, 4, 0 },
};
static struct clk_range sam9263_pll_outputs[] = {
{ .min = 80000000, .max = 200000000 },
{ .min = 190000000, .max = 240000000 },
};
static const struct clk_pll_characteristics sam9263_pll_characteristics = {
.input = { .min = 1000000, .max = 32000000 },
.num_output = ARRAY_SIZE(sam9263_pll_outputs),
.output = sam9263_pll_outputs,
.icpll = sam9260_plla_icpll,
.out = sam9260_plla_out,
};
static const struct sck at91sam9263_systemck[] = {
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "udpck", .p = "usbck", .id = 7 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
{ .n = "pck2", .p = "prog2", .id = 10 },
{ .n = "pck3", .p = "prog3", .id = 11 },
};
static const struct pck at91sam9263_periphck[] = {
{ .n = "pioA_clk", .id = 2, },
{ .n = "pioB_clk", .id = 3, },
{ .n = "pioCDE_clk", .id = 4, },
{ .n = "usart0_clk", .id = 7, },
{ .n = "usart1_clk", .id = 8, },
{ .n = "usart2_clk", .id = 9, },
{ .n = "mci0_clk", .id = 10, },
{ .n = "mci1_clk", .id = 11, },
{ .n = "can_clk", .id = 12, },
{ .n = "twi0_clk", .id = 13, },
{ .n = "spi0_clk", .id = 14, },
{ .n = "spi1_clk", .id = 15, },
{ .n = "ssc0_clk", .id = 16, },
{ .n = "ssc1_clk", .id = 17, },
{ .n = "ac97_clk", .id = 18, },
{ .n = "tcb_clk", .id = 19, },
{ .n = "pwm_clk", .id = 20, },
{ .n = "macb0_clk", .id = 21, },
{ .n = "g2de_clk", .id = 23, },
{ .n = "udc_clk", .id = 24, },
{ .n = "isi_clk", .id = 25, },
{ .n = "lcd_clk", .id = 26, },
{ .n = "dma_clk", .id = 27, },
{ .n = "ohci_clk", .id = 29, },
};
static struct at91sam926x_data at91sam9263_data = {
.plla_layout = &at91rm9200_pll_layout,
.plla_characteristics = &sam9263_pll_characteristics,
.pllb_layout = &at91rm9200_pll_layout,
.pllb_characteristics = &sam9263_pll_characteristics,
.mck_characteristics = &sam9263_mck_characteristics,
.sck = at91sam9263_systemck,
.num_sck = ARRAY_SIZE(at91sam9263_systemck),
.pck = at91sam9263_periphck,
.num_pck = ARRAY_SIZE(at91sam9263_periphck),
.num_progck = 4,
};
static void __init at91sam926x_pmc_setup(struct device_node *np,
struct at91sam926x_data *data)
{
const char *slowxtal_name, *mainxtal_name;
struct pmc_data *at91sam9260_pmc;
u32 usb_div[] = { 1, 2, 4, 0 };
const char *parent_names[6];
const char *slck_name;
struct regmap *regmap;
struct clk_hw *hw;
int i;
bool bypass;
i = of_property_match_string(np, "clock-names", "slow_xtal");
if (i < 0)
return;
slowxtal_name = of_clk_get_parent_name(np, i);
i = of_property_match_string(np, "clock-names", "main_xtal");
if (i < 0)
return;
mainxtal_name = of_clk_get_parent_name(np, i);
regmap = syscon_node_to_regmap(np);
if (IS_ERR(regmap))
return;
at91sam9260_pmc = pmc_data_allocate(PMC_MAIN + 1,
ndck(data->sck, data->num_sck),
ndck(data->pck, data->num_pck), 0);
if (!at91sam9260_pmc)
return;
bypass = of_property_read_bool(np, "atmel,osc-bypass");
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
bypass);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_rm9200_main(regmap, "mainck", "main_osc");
if (IS_ERR(hw))
goto err_free;
at91sam9260_pmc->chws[PMC_MAIN] = hw;
if (data->has_slck) {
hw = clk_hw_register_fixed_rate_with_accuracy(NULL,
"slow_rc_osc",
NULL, 0, 32768,
50000000);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = "slow_rc_osc";
parent_names[1] = "slow_xtal";
hw = at91_clk_register_sam9260_slow(regmap, "slck",
parent_names, 2);
if (IS_ERR(hw))
goto err_free;
at91sam9260_pmc->chws[PMC_SLOW] = hw;
slck_name = "slck";
} else {
slck_name = slowxtal_name;
}
hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
data->plla_layout,
data->plla_characteristics);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_pll(regmap, "pllbck", "mainck", 1,
data->pllb_layout,
data->pllb_characteristics);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "pllack";
parent_names[3] = "pllbck";
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
&at91rm9200_master_layout,
data->mck_characteristics);
if (IS_ERR(hw))
goto err_free;
at91sam9260_pmc->chws[PMC_MCK] = hw;
hw = at91rm9200_clk_register_usb(regmap, "usbck", "pllbck", usb_div);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "pllack";
parent_names[3] = "pllbck";
for (i = 0; i < data->num_progck; i++) {
char name[6];
snprintf(name, sizeof(name), "prog%d", i);
hw = at91_clk_register_programmable(regmap, name,
parent_names, 4, i,
&at91rm9200_programmable_layout);
if (IS_ERR(hw))
goto err_free;
}
for (i = 0; i < data->num_sck; i++) {
hw = at91_clk_register_system(regmap, data->sck[i].n,
data->sck[i].p,
data->sck[i].id);
if (IS_ERR(hw))
goto err_free;
at91sam9260_pmc->shws[data->sck[i].id] = hw;
}
for (i = 0; i < data->num_pck; i++) {
hw = at91_clk_register_peripheral(regmap,
data->pck[i].n,
"masterck",
data->pck[i].id);
if (IS_ERR(hw))
goto err_free;
at91sam9260_pmc->phws[data->pck[i].id] = hw;
}
of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9260_pmc);
return;
err_free:
pmc_data_free(at91sam9260_pmc);
}
static void __init at91sam9260_pmc_setup(struct device_node *np)
{
at91sam926x_pmc_setup(np, &at91sam9260_data);
}
CLK_OF_DECLARE_DRIVER(at91sam9260_pmc, "atmel,at91sam9260-pmc",
at91sam9260_pmc_setup);
static void __init at91sam9261_pmc_setup(struct device_node *np)
{
at91sam926x_pmc_setup(np, &at91sam9261_data);
}
CLK_OF_DECLARE_DRIVER(at91sam9261_pmc, "atmel,at91sam9261-pmc",
at91sam9261_pmc_setup);
static void __init at91sam9263_pmc_setup(struct device_node *np)
{
at91sam926x_pmc_setup(np, &at91sam9263_data);
}
CLK_OF_DECLARE_DRIVER(at91sam9263_pmc, "atmel,at91sam9263-pmc",
at91sam9263_pmc_setup);
static void __init at91sam9g20_pmc_setup(struct device_node *np)
{
at91sam926x_pmc_setup(np, &at91sam9g20_data);
}
CLK_OF_DECLARE_DRIVER(at91sam9g20_pmc, "atmel,at91sam9g20-pmc",
at91sam9g20_pmc_setup);

View File

@@ -0,0 +1,171 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
#include <dt-bindings/clock/at91.h>
#include "pmc.h"
static const struct clk_master_characteristics sam9rl_mck_characteristics = {
.output = { .min = 0, .max = 94000000 },
.divisors = { 1, 2, 4, 0 },
};
static u8 sam9rl_plla_out[] = { 0, 2 };
static struct clk_range sam9rl_plla_outputs[] = {
{ .min = 80000000, .max = 200000000 },
{ .min = 190000000, .max = 240000000 },
};
static const struct clk_pll_characteristics sam9rl_plla_characteristics = {
.input = { .min = 1000000, .max = 32000000 },
.num_output = ARRAY_SIZE(sam9rl_plla_outputs),
.output = sam9rl_plla_outputs,
.out = sam9rl_plla_out,
};
static const struct {
char *n;
char *p;
u8 id;
} at91sam9rl_systemck[] = {
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
};
static const struct {
char *n;
u8 id;
} at91sam9rl_periphck[] = {
{ .n = "pioA_clk", .id = 2, },
{ .n = "pioB_clk", .id = 3, },
{ .n = "pioC_clk", .id = 4, },
{ .n = "pioD_clk", .id = 5, },
{ .n = "usart0_clk", .id = 6, },
{ .n = "usart1_clk", .id = 7, },
{ .n = "usart2_clk", .id = 8, },
{ .n = "usart3_clk", .id = 9, },
{ .n = "mci0_clk", .id = 10, },
{ .n = "twi0_clk", .id = 11, },
{ .n = "twi1_clk", .id = 12, },
{ .n = "spi0_clk", .id = 13, },
{ .n = "ssc0_clk", .id = 14, },
{ .n = "ssc1_clk", .id = 15, },
{ .n = "tc0_clk", .id = 16, },
{ .n = "tc1_clk", .id = 17, },
{ .n = "tc2_clk", .id = 18, },
{ .n = "pwm_clk", .id = 19, },
{ .n = "adc_clk", .id = 20, },
{ .n = "dma0_clk", .id = 21, },
{ .n = "udphs_clk", .id = 22, },
{ .n = "lcd_clk", .id = 23, },
};
static void __init at91sam9rl_pmc_setup(struct device_node *np)
{
const char *slck_name, *mainxtal_name;
struct pmc_data *at91sam9rl_pmc;
const char *parent_names[6];
struct regmap *regmap;
struct clk_hw *hw;
int i;
i = of_property_match_string(np, "clock-names", "slow_clk");
if (i < 0)
return;
slck_name = of_clk_get_parent_name(np, i);
i = of_property_match_string(np, "clock-names", "main_xtal");
if (i < 0)
return;
mainxtal_name = of_clk_get_parent_name(np, i);
regmap = syscon_node_to_regmap(np);
if (IS_ERR(regmap))
return;
at91sam9rl_pmc = pmc_data_allocate(PMC_MAIN + 1,
nck(at91sam9rl_systemck),
nck(at91sam9rl_periphck), 0);
if (!at91sam9rl_pmc)
return;
hw = at91_clk_register_rm9200_main(regmap, "mainck", mainxtal_name);
if (IS_ERR(hw))
goto err_free;
at91sam9rl_pmc->chws[PMC_MAIN] = hw;
hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
&at91rm9200_pll_layout,
&sam9rl_plla_characteristics);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
at91sam9rl_pmc->chws[PMC_UTMI] = hw;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "pllack";
parent_names[3] = "utmick";
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
&at91rm9200_master_layout,
&sam9rl_mck_characteristics);
if (IS_ERR(hw))
goto err_free;
at91sam9rl_pmc->chws[PMC_MCK] = hw;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "pllack";
parent_names[3] = "utmick";
parent_names[4] = "masterck";
for (i = 0; i < 2; i++) {
char name[6];
snprintf(name, sizeof(name), "prog%d", i);
hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i,
&at91rm9200_programmable_layout);
if (IS_ERR(hw))
goto err_free;
}
for (i = 0; i < ARRAY_SIZE(at91sam9rl_systemck); i++) {
hw = at91_clk_register_system(regmap, at91sam9rl_systemck[i].n,
at91sam9rl_systemck[i].p,
at91sam9rl_systemck[i].id);
if (IS_ERR(hw))
goto err_free;
at91sam9rl_pmc->shws[at91sam9rl_systemck[i].id] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91sam9rl_periphck); i++) {
hw = at91_clk_register_peripheral(regmap,
at91sam9rl_periphck[i].n,
"masterck",
at91sam9rl_periphck[i].id);
if (IS_ERR(hw))
goto err_free;
at91sam9rl_pmc->phws[at91sam9rl_periphck[i].id] = hw;
}
of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9rl_pmc);
return;
err_free:
pmc_data_free(at91sam9rl_pmc);
}
CLK_OF_DECLARE_DRIVER(at91sam9rl_pmc, "atmel,at91sam9rl-pmc", at91sam9rl_pmc_setup);

View File

@@ -0,0 +1,309 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
#include <dt-bindings/clock/at91.h>
#include "pmc.h"
static const struct clk_master_characteristics mck_characteristics = {
.output = { .min = 0, .max = 133333333 },
.divisors = { 1, 2, 4, 3 },
.have_div3_pres = 1,
};
static u8 plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 };
static u16 plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 };
static struct clk_range plla_outputs[] = {
{ .min = 745000000, .max = 800000000 },
{ .min = 695000000, .max = 750000000 },
{ .min = 645000000, .max = 700000000 },
{ .min = 595000000, .max = 650000000 },
{ .min = 545000000, .max = 600000000 },
{ .min = 495000000, .max = 555000000 },
{ .min = 445000000, .max = 500000000 },
{ .min = 400000000, .max = 450000000 },
};
static const struct clk_pll_characteristics plla_characteristics = {
.input = { .min = 2000000, .max = 32000000 },
.num_output = ARRAY_SIZE(plla_outputs),
.output = plla_outputs,
.icpll = plla_icpll,
.out = plla_out,
};
static const struct {
char *n;
char *p;
u8 id;
} at91sam9x5_systemck[] = {
{ .n = "ddrck", .p = "masterck", .id = 2 },
{ .n = "smdck", .p = "smdclk", .id = 4 },
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "udpck", .p = "usbck", .id = 7 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
};
struct pck {
char *n;
u8 id;
};
static const struct pck at91sam9x5_periphck[] = {
{ .n = "pioAB_clk", .id = 2, },
{ .n = "pioCD_clk", .id = 3, },
{ .n = "smd_clk", .id = 4, },
{ .n = "usart0_clk", .id = 5, },
{ .n = "usart1_clk", .id = 6, },
{ .n = "usart2_clk", .id = 7, },
{ .n = "twi0_clk", .id = 9, },
{ .n = "twi1_clk", .id = 10, },
{ .n = "twi2_clk", .id = 11, },
{ .n = "mci0_clk", .id = 12, },
{ .n = "spi0_clk", .id = 13, },
{ .n = "spi1_clk", .id = 14, },
{ .n = "uart0_clk", .id = 15, },
{ .n = "uart1_clk", .id = 16, },
{ .n = "tcb0_clk", .id = 17, },
{ .n = "pwm_clk", .id = 18, },
{ .n = "adc_clk", .id = 19, },
{ .n = "dma0_clk", .id = 20, },
{ .n = "dma1_clk", .id = 21, },
{ .n = "uhphs_clk", .id = 22, },
{ .n = "udphs_clk", .id = 23, },
{ .n = "mci1_clk", .id = 26, },
{ .n = "ssc0_clk", .id = 28, },
};
static const struct pck at91sam9g15_periphck[] = {
{ .n = "lcdc_clk", .id = 25, },
{ /* sentinel */}
};
static const struct pck at91sam9g25_periphck[] = {
{ .n = "usart3_clk", .id = 8, },
{ .n = "macb0_clk", .id = 24, },
{ .n = "isi_clk", .id = 25, },
{ /* sentinel */}
};
static const struct pck at91sam9g35_periphck[] = {
{ .n = "macb0_clk", .id = 24, },
{ .n = "lcdc_clk", .id = 25, },
{ /* sentinel */}
};
static const struct pck at91sam9x25_periphck[] = {
{ .n = "usart3_clk", .id = 8, },
{ .n = "macb0_clk", .id = 24, },
{ .n = "macb1_clk", .id = 27, },
{ .n = "can0_clk", .id = 29, },
{ .n = "can1_clk", .id = 30, },
{ /* sentinel */}
};
static const struct pck at91sam9x35_periphck[] = {
{ .n = "macb0_clk", .id = 24, },
{ .n = "lcdc_clk", .id = 25, },
{ .n = "can0_clk", .id = 29, },
{ .n = "can1_clk", .id = 30, },
{ /* sentinel */}
};
static void __init at91sam9x5_pmc_setup(struct device_node *np,
const struct pck *extra_pcks,
bool has_lcdck)
{
struct clk_range range = CLK_RANGE(0, 0);
const char *slck_name, *mainxtal_name;
struct pmc_data *at91sam9x5_pmc;
const char *parent_names[6];
struct regmap *regmap;
struct clk_hw *hw;
int i;
bool bypass;
i = of_property_match_string(np, "clock-names", "slow_clk");
if (i < 0)
return;
slck_name = of_clk_get_parent_name(np, i);
i = of_property_match_string(np, "clock-names", "main_xtal");
if (i < 0)
return;
mainxtal_name = of_clk_get_parent_name(np, i);
regmap = syscon_node_to_regmap(np);
if (IS_ERR(regmap))
return;
at91sam9x5_pmc = pmc_data_allocate(PMC_MAIN + 1,
nck(at91sam9x5_systemck),
nck(at91sam9x35_periphck), 0);
if (!at91sam9x5_pmc)
return;
hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
50000000);
if (IS_ERR(hw))
goto err_free;
bypass = of_property_read_bool(np, "atmel,osc-bypass");
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
bypass);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = "main_rc_osc";
parent_names[1] = "main_osc";
hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2);
if (IS_ERR(hw))
goto err_free;
at91sam9x5_pmc->chws[PMC_MAIN] = hw;
hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
&at91rm9200_pll_layout, &plla_characteristics);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack");
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
at91sam9x5_pmc->chws[PMC_UTMI] = hw;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
parent_names[3] = "utmick";
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
&at91sam9x5_master_layout,
&mck_characteristics);
if (IS_ERR(hw))
goto err_free;
at91sam9x5_pmc->chws[PMC_MCK] = hw;
parent_names[0] = "plladivck";
parent_names[1] = "utmick";
hw = at91sam9x5_clk_register_usb(regmap, "usbck", parent_names, 2);
if (IS_ERR(hw))
goto err_free;
hw = at91sam9x5_clk_register_smd(regmap, "smdclk", parent_names, 2);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
parent_names[3] = "utmick";
parent_names[4] = "mck";
for (i = 0; i < 2; i++) {
char name[6];
snprintf(name, sizeof(name), "prog%d", i);
hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i,
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
}
for (i = 0; i < ARRAY_SIZE(at91sam9x5_systemck); i++) {
hw = at91_clk_register_system(regmap, at91sam9x5_systemck[i].n,
at91sam9x5_systemck[i].p,
at91sam9x5_systemck[i].id);
if (IS_ERR(hw))
goto err_free;
at91sam9x5_pmc->shws[at91sam9x5_systemck[i].id] = hw;
}
if (has_lcdck) {
hw = at91_clk_register_system(regmap, "lcdck", "masterck", 3);
if (IS_ERR(hw))
goto err_free;
at91sam9x5_pmc->shws[3] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91sam9x5_periphck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
at91sam9x5_periphck[i].n,
"masterck",
at91sam9x5_periphck[i].id,
&range);
if (IS_ERR(hw))
goto err_free;
at91sam9x5_pmc->phws[at91sam9x5_periphck[i].id] = hw;
}
for (i = 0; extra_pcks[i].id; i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
extra_pcks[i].n,
"masterck",
extra_pcks[i].id,
&range);
if (IS_ERR(hw))
goto err_free;
at91sam9x5_pmc->phws[extra_pcks[i].id] = hw;
}
of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9x5_pmc);
return;
err_free:
pmc_data_free(at91sam9x5_pmc);
}
static void __init at91sam9g15_pmc_setup(struct device_node *np)
{
at91sam9x5_pmc_setup(np, at91sam9g15_periphck, true);
}
CLK_OF_DECLARE_DRIVER(at91sam9g15_pmc, "atmel,at91sam9g15-pmc",
at91sam9g15_pmc_setup);
static void __init at91sam9g25_pmc_setup(struct device_node *np)
{
at91sam9x5_pmc_setup(np, at91sam9g25_periphck, false);
}
CLK_OF_DECLARE_DRIVER(at91sam9g25_pmc, "atmel,at91sam9g25-pmc",
at91sam9g25_pmc_setup);
static void __init at91sam9g35_pmc_setup(struct device_node *np)
{
at91sam9x5_pmc_setup(np, at91sam9g35_periphck, true);
}
CLK_OF_DECLARE_DRIVER(at91sam9g35_pmc, "atmel,at91sam9g35-pmc",
at91sam9g35_pmc_setup);
static void __init at91sam9x25_pmc_setup(struct device_node *np)
{
at91sam9x5_pmc_setup(np, at91sam9x25_periphck, false);
}
CLK_OF_DECLARE_DRIVER(at91sam9x25_pmc, "atmel,at91sam9x25-pmc",
at91sam9x25_pmc_setup);
static void __init at91sam9x35_pmc_setup(struct device_node *np)
{
at91sam9x5_pmc_setup(np, at91sam9x35_periphck, true);
}
CLK_OF_DECLARE_DRIVER(at91sam9x35_pmc, "atmel,at91sam9x35-pmc",
at91sam9x35_pmc_setup);

View File

@@ -43,6 +43,8 @@
#include <linux/regmap.h>
#include <linux/slab.h>
#include "pmc.h"
#define AUDIO_PLL_DIV_FRAC BIT(22)
#define AUDIO_PLL_ND_MAX (AT91_PMC_AUDIO_PLL_ND_MASK >> \
AT91_PMC_AUDIO_PLL_ND_OFFSET)
@@ -444,93 +446,94 @@ static const struct clk_ops audio_pll_pmc_ops = {
.set_rate = clk_audio_pll_pmc_set_rate,
};
static int of_sama5d2_clk_audio_pll_setup(struct device_node *np,
struct clk_init_data *init,
struct clk_hw *hw,
struct regmap **clk_audio_regmap)
{
struct regmap *regmap;
const char *parent_names[1];
int ret;
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return PTR_ERR(regmap);
init->name = np->name;
of_clk_parent_fill(np, parent_names, 1);
init->parent_names = parent_names;
init->num_parents = 1;
hw->init = init;
*clk_audio_regmap = regmap;
ret = clk_hw_register(NULL, hw);
if (ret)
return ret;
return of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
struct clk_hw * __init
at91_clk_register_audio_pll_frac(struct regmap *regmap, const char *name,
const char *parent_name)
{
struct clk_audio_frac *frac_ck;
struct clk_init_data init = {};
int ret;
frac_ck = kzalloc(sizeof(*frac_ck), GFP_KERNEL);
if (!frac_ck)
return;
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &audio_pll_frac_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
init.flags = CLK_SET_RATE_GATE;
if (of_sama5d2_clk_audio_pll_setup(np, &init, &frac_ck->hw,
&frac_ck->regmap))
frac_ck->hw.init = &init;
frac_ck->regmap = regmap;
ret = clk_hw_register(NULL, &frac_ck->hw);
if (ret) {
kfree(frac_ck);
return ERR_PTR(ret);
}
return &frac_ck->hw;
}
static void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np)
struct clk_hw * __init
at91_clk_register_audio_pll_pad(struct regmap *regmap, const char *name,
const char *parent_name)
{
struct clk_audio_pad *apad_ck;
struct clk_init_data init = {};
struct clk_init_data init;
int ret;
apad_ck = kzalloc(sizeof(*apad_ck), GFP_KERNEL);
if (!apad_ck)
return;
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &audio_pll_pad_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
CLK_SET_RATE_PARENT;
if (of_sama5d2_clk_audio_pll_setup(np, &init, &apad_ck->hw,
&apad_ck->regmap))
apad_ck->hw.init = &init;
apad_ck->regmap = regmap;
ret = clk_hw_register(NULL, &apad_ck->hw);
if (ret) {
kfree(apad_ck);
return ERR_PTR(ret);
}
return &apad_ck->hw;
}
static void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np)
struct clk_hw * __init
at91_clk_register_audio_pll_pmc(struct regmap *regmap, const char *name,
const char *parent_name)
{
struct clk_audio_pad *apmc_ck;
struct clk_init_data init = {};
struct clk_audio_pmc *apmc_ck;
struct clk_init_data init;
int ret;
apmc_ck = kzalloc(sizeof(*apmc_ck), GFP_KERNEL);
if (!apmc_ck)
return;
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &audio_pll_pmc_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
CLK_SET_RATE_PARENT;
if (of_sama5d2_clk_audio_pll_setup(np, &init, &apmc_ck->hw,
&apmc_ck->regmap))
kfree(apmc_ck);
}
apmc_ck->hw.init = &init;
apmc_ck->regmap = regmap;
CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_frac_setup,
"atmel,sama5d2-clk-audio-pll-frac",
of_sama5d2_clk_audio_pll_frac_setup);
CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pad_setup,
"atmel,sama5d2-clk-audio-pll-pad",
of_sama5d2_clk_audio_pll_pad_setup);
CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup,
"atmel,sama5d2-clk-audio-pll-pmc",
of_sama5d2_clk_audio_pll_pmc_setup);
ret = clk_hw_register(NULL, &apmc_ck->hw);
if (ret) {
kfree(apmc_ck);
return ERR_PTR(ret);
}
return &apmc_ck->hw;
}

View File

@@ -20,17 +20,8 @@
#include "pmc.h"
#define PERIPHERAL_MAX 64
#define PERIPHERAL_ID_MIN 2
#define GENERATED_SOURCE_MAX 6
#define GENERATED_MAX_DIV 255
#define GCK_ID_SSC0 43
#define GCK_ID_SSC1 44
#define GCK_ID_I2S0 54
#define GCK_ID_I2S1 55
#define GCK_ID_CLASSD 59
#define GCK_INDEX_DT_AUDIO_PLL 5
struct clk_generated {
@@ -279,10 +270,10 @@ static void clk_generated_startup(struct clk_generated *gck)
>> AT91_PMC_PCR_GCKDIV_OFFSET;
}
static struct clk_hw * __init
struct clk_hw * __init
at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
const char *name, const char **parent_names,
u8 num_parents, u8 id,
u8 num_parents, u8 id, bool pll_audio,
const struct clk_range *range)
{
struct clk_generated *gck;
@@ -306,6 +297,7 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
gck->regmap = regmap;
gck->lock = lock;
gck->range = *range;
gck->audio_pll_allowed = pll_audio;
clk_generated_startup(gck);
hw = &gck->hw;
@@ -319,70 +311,3 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
return hw;
}
static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
{
int num;
u32 id;
const char *name;
struct clk_hw *hw;
unsigned int num_parents;
const char *parent_names[GENERATED_SOURCE_MAX];
struct device_node *gcknp;
struct clk_range range = CLK_RANGE(0, 0);
struct regmap *regmap;
struct clk_generated *gck;
num_parents = of_clk_get_parent_count(np);
if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX)
return;
of_clk_parent_fill(np, parent_names, num_parents);
num = of_get_child_count(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;
if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX)
continue;
if (of_property_read_string(np, "clock-output-names", &name))
name = gcknp->name;
of_at91_get_clk_range(gcknp, "atmel,clk-output-range",
&range);
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
parent_names, num_parents,
id, &range);
gck = to_clk_generated(hw);
if (of_device_is_compatible(np,
"atmel,sama5d2-clk-generated")) {
if (gck->id == GCK_ID_SSC0 || gck->id == GCK_ID_SSC1 ||
gck->id == GCK_ID_I2S0 || gck->id == GCK_ID_I2S1 ||
gck->id == GCK_ID_CLASSD)
gck->audio_pll_allowed = true;
else
gck->audio_pll_allowed = false;
} else {
gck->audio_pll_allowed = false;
}
if (IS_ERR(hw))
continue;
of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw);
}
}
CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated",
of_sama5d2_clk_generated_setup);

View File

@@ -86,25 +86,19 @@ static const struct clk_ops h32mx_ops = {
.set_rate = clk_sama5d4_h32mx_set_rate,
};
static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np)
struct clk_hw * __init
at91_clk_register_h32mx(struct regmap *regmap, const char *name,
const char *parent_name)
{
struct clk_sama5d4_h32mx *h32mxclk;
struct clk_init_data init;
const char *parent_name;
struct regmap *regmap;
int ret;
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
h32mxclk = kzalloc(sizeof(*h32mxclk), GFP_KERNEL);
if (!h32mxclk)
return;
return ERR_PTR(-ENOMEM);
parent_name = of_clk_get_parent_name(np, 0);
init.name = np->name;
init.name = name;
init.ops = &h32mx_ops;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
@@ -116,10 +110,8 @@ static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np)
ret = clk_hw_register(NULL, &h32mxclk->hw);
if (ret) {
kfree(h32mxclk);
return;
return ERR_PTR(ret);
}
of_clk_add_hw_provider(np, of_clk_hw_simple_get, &h32mxclk->hw);
return &h32mxclk->hw;
}
CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx",
of_sama5d4_clk_h32mx_setup);

View File

@@ -14,7 +14,7 @@
#include <soc/at91/atmel-sfr.h>
#define I2S_BUS_NR 2
#include "pmc.h"
struct clk_i2s_mux {
struct clk_hw hw;
@@ -48,7 +48,7 @@ static const struct clk_ops clk_i2s_mux_ops = {
.determine_rate = __clk_mux_determine_rate,
};
static struct clk_hw * __init
struct clk_hw * __init
at91_clk_i2s_mux_register(struct regmap *regmap, const char *name,
const char * const *parent_names,
unsigned int num_parents, u8 bus_id)
@@ -78,39 +78,3 @@ at91_clk_i2s_mux_register(struct regmap *regmap, const char *name,
return &i2s_ck->hw;
}
static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np)
{
struct regmap *regmap_sfr;
u8 bus_id;
const char *parent_names[2];
struct device_node *i2s_mux_np;
struct clk_hw *hw;
int ret;
regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
if (IS_ERR(regmap_sfr))
return;
for_each_child_of_node(np, i2s_mux_np) {
if (of_property_read_u8(i2s_mux_np, "reg", &bus_id))
continue;
if (bus_id > I2S_BUS_NR)
continue;
ret = of_clk_parent_fill(i2s_mux_np, parent_names, 2);
if (ret != 2)
continue;
hw = at91_clk_i2s_mux_register(regmap_sfr, i2s_mux_np->name,
parent_names, 2, bus_id);
if (IS_ERR(hw))
continue;
of_clk_add_hw_provider(i2s_mux_np, of_clk_hw_simple_get, hw);
}
}
CLK_OF_DECLARE(sama5d2_clk_i2s_mux, "atmel,sama5d2-clk-i2s-mux",
of_sama5d2_clk_i2s_mux_setup);

View File

@@ -12,7 +12,6 @@
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
@@ -128,7 +127,7 @@ static const struct clk_ops main_osc_ops = {
.is_prepared = clk_main_osc_is_prepared,
};
static struct clk_hw * __init
struct clk_hw * __init
at91_clk_register_main_osc(struct regmap *regmap,
const char *name,
const char *parent_name,
@@ -171,31 +170,6 @@ at91_clk_register_main_osc(struct regmap *regmap,
return hw;
}
static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np)
{
struct clk_hw *hw;
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);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91_clk_register_main_osc(regmap, name, parent_name, bypass);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc",
of_at91rm9200_clk_main_osc_setup);
static bool clk_main_rc_osc_ready(struct regmap *regmap)
{
unsigned int status;
@@ -275,7 +249,7 @@ static const struct clk_ops main_rc_osc_ops = {
.recalc_accuracy = clk_main_rc_osc_recalc_accuracy,
};
static struct clk_hw * __init
struct clk_hw * __init
at91_clk_register_main_rc_osc(struct regmap *regmap,
const char *name,
u32 frequency, u32 accuracy)
@@ -313,32 +287,6 @@ at91_clk_register_main_rc_osc(struct regmap *regmap,
return hw;
}
static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np)
{
struct clk_hw *hw;
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);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
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 regmap *regmap)
{
unsigned long prep_time, timeout;
@@ -403,7 +351,7 @@ static const struct clk_ops rm9200_main_ops = {
.recalc_rate = clk_rm9200_main_recalc_rate,
};
static struct clk_hw * __init
struct clk_hw * __init
at91_clk_register_rm9200_main(struct regmap *regmap,
const char *name,
const char *parent_name)
@@ -442,29 +390,6 @@ at91_clk_register_rm9200_main(struct regmap *regmap,
return hw;
}
static void __init of_at91rm9200_clk_main_setup(struct device_node *np)
{
struct clk_hw *hw;
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);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91_clk_register_rm9200_main(regmap, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main",
of_at91rm9200_clk_main_setup);
static inline bool clk_sam9x5_main_ready(struct regmap *regmap)
{
unsigned int status;
@@ -541,7 +466,7 @@ static const struct clk_ops sam9x5_main_ops = {
.get_parent = clk_sam9x5_main_get_parent,
};
static struct clk_hw * __init
struct clk_hw * __init
at91_clk_register_sam9x5_main(struct regmap *regmap,
const char *name,
const char **parent_names,
@@ -583,32 +508,3 @@ at91_clk_register_sam9x5_main(struct regmap *regmap,
return hw;
}
static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *parent_names[2];
unsigned int num_parents;
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);
hw = at91_clk_register_sam9x5_main(regmap, name, parent_names,
num_parents);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main",
of_at91sam9x5_clk_main_setup);

View File

@@ -17,24 +17,11 @@
#include "pmc.h"
#define MASTER_SOURCE_MAX 4
#define MASTER_PRES_MASK 0x7
#define MASTER_PRES_MAX MASTER_PRES_MASK
#define MASTER_DIV_SHIFT 8
#define MASTER_DIV_MASK 0x3
struct clk_master_characteristics {
struct clk_range output;
u32 divisors[4];
u8 have_div3_pres;
};
struct clk_master_layout {
u32 mask;
u8 pres_shift;
};
#define to_clk_master(hw) container_of(hw, struct clk_master, hw)
struct clk_master {
@@ -120,7 +107,7 @@ static const struct clk_ops master_ops = {
.get_parent = clk_master_get_parent,
};
static struct clk_hw * __init
struct clk_hw * __init
at91_clk_register_master(struct regmap *regmap,
const char *name, int num_parents,
const char **parent_names,
@@ -161,92 +148,12 @@ at91_clk_register_master(struct regmap *regmap,
}
static const struct clk_master_layout at91rm9200_master_layout = {
const struct clk_master_layout at91rm9200_master_layout = {
.mask = 0x31F,
.pres_shift = 2,
};
static const struct clk_master_layout at91sam9x5_master_layout = {
const struct clk_master_layout at91sam9x5_master_layout = {
.mask = 0x373,
.pres_shift = 4,
};
static struct clk_master_characteristics * __init
of_at91_clk_master_get_characteristics(struct device_node *np)
{
struct clk_master_characteristics *characteristics;
characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
if (!characteristics)
return NULL;
if (of_at91_get_clk_range(np, "atmel,clk-output-range", &characteristics->output))
goto out_free_characteristics;
of_property_read_u32_array(np, "atmel,clk-divisors",
characteristics->divisors, 4);
characteristics->have_div3_pres =
of_property_read_bool(np, "atmel,master-clk-have-div3-pres");
return characteristics;
out_free_characteristics:
kfree(characteristics);
return NULL;
}
static void __init
of_at91_clk_master_setup(struct device_node *np,
const struct clk_master_layout *layout)
{
struct clk_hw *hw;
unsigned int num_parents;
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)
return;
of_clk_parent_fill(np, parent_names, num_parents);
of_property_read_string(np, "clock-output-names", &name);
characteristics = of_at91_clk_master_get_characteristics(np);
if (!characteristics)
return;
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91_clk_register_master(regmap, name, num_parents,
parent_names, layout,
characteristics);
if (IS_ERR(hw))
goto out_free_characteristics;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
return;
out_free_characteristics:
kfree(characteristics);
}
static void __init of_at91rm9200_clk_master_setup(struct device_node *np)
{
of_at91_clk_master_setup(np, &at91rm9200_master_layout);
}
CLK_OF_DECLARE(at91rm9200_clk_master, "atmel,at91rm9200-clk-master",
of_at91rm9200_clk_master_setup);
static void __init of_at91sam9x5_clk_master_setup(struct device_node *np)
{
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

@@ -19,11 +19,6 @@
DEFINE_SPINLOCK(pmc_pcr_lock);
#define PERIPHERAL_MAX 64
#define PERIPHERAL_AT91RM9200 0
#define PERIPHERAL_AT91SAM9X5 1
#define PERIPHERAL_ID_MIN 2
#define PERIPHERAL_ID_MAX 31
#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
@@ -104,7 +99,7 @@ static const struct clk_ops peripheral_ops = {
.is_enabled = clk_peripheral_is_enabled,
};
static struct clk_hw * __init
struct clk_hw * __init
at91_clk_register_peripheral(struct regmap *regmap, const char *name,
const char *parent_name, u32 id)
{
@@ -331,7 +326,7 @@ static const struct clk_ops sam9x5_peripheral_ops = {
.set_rate = clk_sam9x5_peripheral_set_rate,
};
static struct clk_hw * __init
struct clk_hw * __init
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)
@@ -374,75 +369,3 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
return hw;
}
static void __init
of_at91_clk_periph_setup(struct device_node *np, u8 type)
{
int num;
u32 id;
struct clk_hw *hw;
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)
return;
num = of_get_child_count(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, periphclknp) {
if (of_property_read_u32(periphclknp, "reg", &id))
continue;
if (id >= PERIPHERAL_MAX)
continue;
if (of_property_read_string(np, "clock-output-names", &name))
name = periphclknp->name;
if (type == PERIPHERAL_AT91RM9200) {
hw = at91_clk_register_peripheral(regmap, name,
parent_name, id);
} else {
struct clk_range range = CLK_RANGE(0, 0);
of_at91_get_clk_range(periphclknp,
"atmel,clk-output-range",
&range);
hw = at91_clk_register_sam9x5_peripheral(regmap,
&pmc_pcr_lock,
name,
parent_name,
id, &range);
}
if (IS_ERR(hw))
continue;
of_clk_add_hw_provider(periphclknp, of_clk_hw_simple_get, hw);
}
}
static void __init of_at91rm9200_clk_periph_setup(struct device_node *np)
{
of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200);
}
CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral",
of_at91rm9200_clk_periph_setup);
static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np)
{
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

@@ -34,20 +34,6 @@
#define PLL_OUT_SHIFT 14
#define PLL_MAX_ID 1
struct clk_pll_characteristics {
struct clk_range input;
int num_output;
struct clk_range *output;
u16 *icpll;
u8 *out;
};
struct clk_pll_layout {
u32 pllr_mask;
u16 mul_mask;
u8 mul_shift;
};
#define to_clk_pll(hw) container_of(hw, struct clk_pll, hw)
struct clk_pll {
@@ -133,6 +119,9 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
{
struct clk_pll *pll = to_clk_pll(hw);
if (!pll->div || !pll->mul)
return 0;
return (parent_rate / pll->div) * (pll->mul + 1);
}
@@ -285,7 +274,7 @@ static const struct clk_ops pll_ops = {
.set_rate = clk_pll_set_rate,
};
static struct clk_hw * __init
struct clk_hw * __init
at91_clk_register_pll(struct regmap *regmap, const char *name,
const char *parent_name, u8 id,
const struct clk_pll_layout *layout,
@@ -331,189 +320,26 @@ at91_clk_register_pll(struct regmap *regmap, const char *name,
}
static const struct clk_pll_layout at91rm9200_pll_layout = {
const struct clk_pll_layout at91rm9200_pll_layout = {
.pllr_mask = 0x7FFFFFF,
.mul_shift = 16,
.mul_mask = 0x7FF,
};
static const struct clk_pll_layout at91sam9g45_pll_layout = {
const struct clk_pll_layout at91sam9g45_pll_layout = {
.pllr_mask = 0xFFFFFF,
.mul_shift = 16,
.mul_mask = 0xFF,
};
static const struct clk_pll_layout at91sam9g20_pllb_layout = {
const struct clk_pll_layout at91sam9g20_pllb_layout = {
.pllr_mask = 0x3FFFFF,
.mul_shift = 16,
.mul_mask = 0x3F,
};
static const struct clk_pll_layout sama5d3_pll_layout = {
const struct clk_pll_layout sama5d3_pll_layout = {
.pllr_mask = 0x1FFFFFF,
.mul_shift = 18,
.mul_mask = 0x7F,
};
static struct clk_pll_characteristics * __init
of_at91_clk_pll_get_characteristics(struct device_node *np)
{
int i;
int offset;
u32 tmp;
int num_output;
u32 num_cells;
struct clk_range input;
struct clk_range *output;
u8 *out = NULL;
u16 *icpll = NULL;
struct clk_pll_characteristics *characteristics;
if (of_at91_get_clk_range(np, "atmel,clk-input-range", &input))
return NULL;
if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells",
&num_cells))
return NULL;
if (num_cells < 2 || num_cells > 4)
return NULL;
if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp))
return NULL;
num_output = tmp / (sizeof(u32) * num_cells);
characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
if (!characteristics)
return NULL;
output = kcalloc(num_output, sizeof(*output), GFP_KERNEL);
if (!output)
goto out_free_characteristics;
if (num_cells > 2) {
out = kcalloc(num_output, sizeof(*out), GFP_KERNEL);
if (!out)
goto out_free_output;
}
if (num_cells > 3) {
icpll = kcalloc(num_output, sizeof(*icpll), GFP_KERNEL);
if (!icpll)
goto out_free_output;
}
for (i = 0; i < num_output; i++) {
offset = i * num_cells;
if (of_property_read_u32_index(np,
"atmel,pll-clk-output-ranges",
offset, &tmp))
goto out_free_output;
output[i].min = tmp;
if (of_property_read_u32_index(np,
"atmel,pll-clk-output-ranges",
offset + 1, &tmp))
goto out_free_output;
output[i].max = tmp;
if (num_cells == 2)
continue;
if (of_property_read_u32_index(np,
"atmel,pll-clk-output-ranges",
offset + 2, &tmp))
goto out_free_output;
out[i] = tmp;
if (num_cells == 3)
continue;
if (of_property_read_u32_index(np,
"atmel,pll-clk-output-ranges",
offset + 3, &tmp))
goto out_free_output;
icpll[i] = tmp;
}
characteristics->input = input;
characteristics->num_output = num_output;
characteristics->output = output;
characteristics->out = out;
characteristics->icpll = icpll;
return characteristics;
out_free_output:
kfree(icpll);
kfree(out);
kfree(output);
out_free_characteristics:
kfree(characteristics);
return NULL;
}
static void __init
of_at91_clk_pll_setup(struct device_node *np,
const struct clk_pll_layout *layout)
{
u32 id;
struct clk_hw *hw;
struct regmap *regmap;
const char *parent_name;
const char *name = np->name;
struct clk_pll_characteristics *characteristics;
if (of_property_read_u32(np, "reg", &id))
return;
parent_name = of_clk_get_parent_name(np, 0);
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;
hw = at91_clk_register_pll(regmap, name, parent_name, id, layout,
characteristics);
if (IS_ERR(hw))
goto out_free_characteristics;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
return;
out_free_characteristics:
kfree(characteristics);
}
static void __init of_at91rm9200_clk_pll_setup(struct device_node *np)
{
of_at91_clk_pll_setup(np, &at91rm9200_pll_layout);
}
CLK_OF_DECLARE(at91rm9200_clk_pll, "atmel,at91rm9200-clk-pll",
of_at91rm9200_clk_pll_setup);
static void __init of_at91sam9g45_clk_pll_setup(struct device_node *np)
{
of_at91_clk_pll_setup(np, &at91sam9g45_pll_layout);
}
CLK_OF_DECLARE(at91sam9g45_clk_pll, "atmel,at91sam9g45-clk-pll",
of_at91sam9g45_clk_pll_setup);
static void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np)
{
of_at91_clk_pll_setup(np, &at91sam9g20_pllb_layout);
}
CLK_OF_DECLARE(at91sam9g20_clk_pllb, "atmel,at91sam9g20-clk-pllb",
of_at91sam9g20_clk_pllb_setup);
static void __init of_sama5d3_clk_pll_setup(struct device_node *np)
{
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

@@ -75,7 +75,7 @@ static const struct clk_ops plldiv_ops = {
.set_rate = clk_plldiv_set_rate,
};
static struct clk_hw * __init
struct clk_hw * __init
at91_clk_register_plldiv(struct regmap *regmap, const char *name,
const char *parent_name)
{
@@ -106,28 +106,3 @@ at91_clk_register_plldiv(struct regmap *regmap, const char *name,
return hw;
}
static void __init
of_at91sam9x5_clk_plldiv_setup(struct device_node *np)
{
struct clk_hw *hw;
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);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91_clk_register_plldiv(regmap, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv",
of_at91sam9x5_clk_plldiv_setup);

View File

@@ -17,7 +17,6 @@
#include "pmc.h"
#define PROG_SOURCE_MAX 5
#define PROG_ID_MAX 7
#define PROG_STATUS_MASK(id) (1 << ((id) + 8))
@@ -25,12 +24,6 @@
#define PROG_PRES(layout, pckr) ((pckr >> layout->pres_shift) & PROG_PRES_MASK)
#define PROG_MAX_RM9200_CSS 3
struct clk_programmable_layout {
u8 pres_shift;
u8 css_mask;
u8 have_slck_mck;
};
struct clk_programmable {
struct clk_hw hw;
struct regmap *regmap;
@@ -170,7 +163,7 @@ static const struct clk_ops programmable_ops = {
.set_rate = clk_programmable_set_rate,
};
static struct clk_hw * __init
struct clk_hw * __init
at91_clk_register_programmable(struct regmap *regmap,
const char *name, const char **parent_names,
u8 num_parents, u8 id,
@@ -211,86 +204,20 @@ at91_clk_register_programmable(struct regmap *regmap,
return hw;
}
static const struct clk_programmable_layout at91rm9200_programmable_layout = {
const struct clk_programmable_layout at91rm9200_programmable_layout = {
.pres_shift = 2,
.css_mask = 0x3,
.have_slck_mck = 0,
};
static const struct clk_programmable_layout at91sam9g45_programmable_layout = {
const struct clk_programmable_layout at91sam9g45_programmable_layout = {
.pres_shift = 2,
.css_mask = 0x3,
.have_slck_mck = 1,
};
static const struct clk_programmable_layout at91sam9x5_programmable_layout = {
const struct clk_programmable_layout at91sam9x5_programmable_layout = {
.pres_shift = 4,
.css_mask = 0x7,
.have_slck_mck = 0,
};
static void __init
of_at91_clk_prog_setup(struct device_node *np,
const struct clk_programmable_layout *layout)
{
int num;
u32 id;
struct clk_hw *hw;
unsigned int num_parents;
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)
return;
of_clk_parent_fill(np, parent_names, num_parents);
num = of_get_child_count(np);
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;
if (of_property_read_string(np, "clock-output-names", &name))
name = progclknp->name;
hw = at91_clk_register_programmable(regmap, name,
parent_names, num_parents,
id, layout);
if (IS_ERR(hw))
continue;
of_clk_add_hw_provider(progclknp, of_clk_hw_simple_get, hw);
}
}
static void __init of_at91rm9200_clk_prog_setup(struct device_node *np)
{
of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout);
}
CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable",
of_at91rm9200_clk_prog_setup);
static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np)
{
of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout);
}
CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable",
of_at91sam9g45_clk_prog_setup);
static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np)
{
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

@@ -40,7 +40,7 @@ static const struct clk_ops sam9260_slow_ops = {
.get_parent = clk_sam9260_slow_get_parent,
};
static struct clk_hw * __init
struct clk_hw * __init
at91_clk_register_sam9260_slow(struct regmap *regmap,
const char *name,
const char **parent_names,
@@ -79,33 +79,3 @@ at91_clk_register_sam9260_slow(struct regmap *regmap,
return hw;
}
static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *parent_names[2];
unsigned 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);
hw = at91_clk_register_sam9260_slow(regmap, name, parent_names,
num_parents);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
of_at91sam9260_clk_slow_setup);

View File

@@ -17,8 +17,6 @@
#include "pmc.h"
#define SMD_SOURCE_MAX 2
#define SMD_DIV_SHIFT 8
#define SMD_MAX_DIV 0xf
@@ -111,7 +109,7 @@ static const struct clk_ops at91sam9x5_smd_ops = {
.set_rate = at91sam9x5_clk_smd_set_rate,
};
static struct clk_hw * __init
struct clk_hw * __init
at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents)
{
@@ -142,33 +140,3 @@ at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name,
return hw;
}
static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np)
{
struct clk_hw *hw;
unsigned 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)
return;
of_clk_parent_fill(np, parent_names, num_parents);
of_property_read_string(np, "clock-output-names", &name);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91sam9x5_clk_register_smd(regmap, name, parent_names,
num_parents);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd",
of_at91sam9x5_clk_smd_setup);

View File

@@ -88,7 +88,7 @@ static const struct clk_ops system_ops = {
.is_prepared = clk_system_is_prepared,
};
static struct clk_hw * __init
struct clk_hw * __init
at91_clk_register_system(struct regmap *regmap, const char *name,
const char *parent_name, u8 id)
{
@@ -123,40 +123,3 @@ at91_clk_register_system(struct regmap *regmap, const char *name,
return hw;
}
static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
{
int num;
u32 id;
struct clk_hw *hw;
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;
if (of_property_read_string(np, "clock-output-names", &name))
name = sysclknp->name;
parent_name = of_clk_get_parent_name(sysclknp, 0);
hw = at91_clk_register_system(regmap, name, parent_name, id);
if (IS_ERR(hw))
continue;
of_clk_add_hw_provider(sysclknp, of_clk_hw_simple_get, hw);
}
}
CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system",
of_at91rm9200_clk_sys_setup);

View File

@@ -17,8 +17,6 @@
#include "pmc.h"
#define USB_SOURCE_MAX 2
#define SAM9X5_USB_DIV_SHIFT 8
#define SAM9X5_USB_MAX_DIV 0xf
@@ -192,7 +190,7 @@ static const struct clk_ops at91sam9n12_usb_ops = {
.set_rate = at91sam9x5_clk_usb_set_rate,
};
static struct clk_hw * __init
struct clk_hw * __init
at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents)
{
@@ -225,7 +223,7 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
return hw;
}
static struct clk_hw * __init
struct clk_hw * __init
at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,
const char *parent_name)
{
@@ -342,7 +340,7 @@ static const struct clk_ops at91rm9200_usb_ops = {
.set_rate = at91rm9200_clk_usb_set_rate,
};
static struct clk_hw * __init
struct clk_hw * __init
at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,
const char *parent_name, const u32 *divisors)
{
@@ -374,89 +372,3 @@ at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,
return hw;
}
static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np)
{
struct clk_hw *hw;
unsigned 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)
return;
of_clk_parent_fill(np, parent_names, num_parents);
of_property_read_string(np, "clock-output-names", &name);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91sam9x5_clk_register_usb(regmap, name, parent_names,
num_parents);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb",
of_at91sam9x5_clk_usb_setup);
static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *parent_name;
const char *name = np->name;
struct regmap *regmap;
parent_name = of_clk_get_parent_name(np, 0);
if (!parent_name)
return;
of_property_read_string(np, "clock-output-names", &name);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91sam9n12_clk_register_usb(regmap, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb",
of_at91sam9n12_clk_usb_setup);
static void __init of_at91rm9200_clk_usb_setup(struct device_node *np)
{
struct clk_hw *hw;
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)
return;
of_property_read_u32_array(np, "atmel,clk-divisors", divisors, 4);
if (!divisors[0])
return;
of_property_read_string(np, "clock-output-names", &name);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb",
of_at91rm9200_clk_usb_setup);

View File

@@ -125,7 +125,7 @@ static const struct clk_ops utmi_ops = {
.recalc_rate = clk_utmi_recalc_rate,
};
static struct clk_hw * __init
struct clk_hw * __init
at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
const char *name, const char *parent_name)
{
@@ -157,46 +157,3 @@ at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
return hw;
}
static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *parent_name;
const char *name = np->name;
struct regmap *regmap_pmc, *regmap_sfr;
parent_name = of_clk_get_parent_name(np, 0);
of_property_read_string(np, "clock-output-names", &name);
regmap_pmc = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap_pmc))
return;
/*
* If the device supports different mainck rates, this value has to be
* set in the UTMI Clock Trimming register.
* - 9x5: mainck supports several rates but it is indicated that a
* 12 MHz is needed in case of USB.
* - sama5d3 and sama5d2: mainck supports several rates. Configuring
* the FREQ field of the UTMI Clock Trimming register is mandatory.
* - sama5d4: mainck is at 12 MHz.
*
* We only need to retrieve sama5d3 or sama5d2 sfr regmap.
*/
regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d3-sfr");
if (IS_ERR(regmap_sfr)) {
regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
if (IS_ERR(regmap_sfr))
regmap_sfr = NULL;
}
hw = at91_clk_register_utmi(regmap_pmc, regmap_sfr, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
return;
}
CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi",
of_at91sam9x5_clk_utmi_setup);

View File

@@ -0,0 +1,961 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk-provider.h>
#include <linux/clk/at91_pmc.h>
#include <linux/of.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include "pmc.h"
#define MASTER_SOURCE_MAX 4
#define PERIPHERAL_AT91RM9200 0
#define PERIPHERAL_AT91SAM9X5 1
#define PERIPHERAL_MAX 64
#define PERIPHERAL_ID_MIN 2
#define PROG_SOURCE_MAX 5
#define PROG_ID_MAX 7
#define SYSTEM_MAX_ID 31
#ifdef CONFIG_HAVE_AT91_AUDIO_PLL
static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *name = np->name;
const char *parent_name;
struct regmap *regmap;
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
parent_name = of_clk_get_parent_name(np, 0);
hw = at91_clk_register_audio_pll_frac(regmap, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_frac_setup,
"atmel,sama5d2-clk-audio-pll-frac",
of_sama5d2_clk_audio_pll_frac_setup);
static void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *name = np->name;
const char *parent_name;
struct regmap *regmap;
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
parent_name = of_clk_get_parent_name(np, 0);
hw = at91_clk_register_audio_pll_pad(regmap, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pad_setup,
"atmel,sama5d2-clk-audio-pll-pad",
of_sama5d2_clk_audio_pll_pad_setup);
static void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *name = np->name;
const char *parent_name;
struct regmap *regmap;
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
parent_name = of_clk_get_parent_name(np, 0);
hw = at91_clk_register_audio_pll_pmc(regmap, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup,
"atmel,sama5d2-clk-audio-pll-pmc",
of_sama5d2_clk_audio_pll_pmc_setup);
#endif /* CONFIG_HAVE_AT91_AUDIO_PLL */
#ifdef CONFIG_HAVE_AT91_GENERATED_CLK
#define GENERATED_SOURCE_MAX 6
#define GCK_ID_I2S0 54
#define GCK_ID_I2S1 55
#define GCK_ID_CLASSD 59
static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
{
int num;
u32 id;
const char *name;
struct clk_hw *hw;
unsigned int num_parents;
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)
return;
of_clk_parent_fill(np, parent_names, num_parents);
num = of_get_child_count(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) {
bool pll_audio = false;
if (of_property_read_u32(gcknp, "reg", &id))
continue;
if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX)
continue;
if (of_property_read_string(np, "clock-output-names", &name))
name = gcknp->name;
of_at91_get_clk_range(gcknp, "atmel,clk-output-range",
&range);
if (of_device_is_compatible(np, "atmel,sama5d2-clk-generated") &&
(id == GCK_ID_I2S0 || id == GCK_ID_I2S1 ||
id == GCK_ID_CLASSD))
pll_audio = true;
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
parent_names, num_parents,
id, pll_audio, &range);
if (IS_ERR(hw))
continue;
of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw);
}
}
CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated",
of_sama5d2_clk_generated_setup);
#endif /* CONFIG_HAVE_AT91_GENERATED_CLK */
#ifdef CONFIG_HAVE_AT91_H32MX
static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *name = np->name;
const char *parent_name;
struct regmap *regmap;
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
parent_name = of_clk_get_parent_name(np, 0);
hw = at91_clk_register_h32mx(regmap, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx",
of_sama5d4_clk_h32mx_setup);
#endif /* CONFIG_HAVE_AT91_H32MX */
#ifdef CONFIG_HAVE_AT91_I2S_MUX_CLK
#define I2S_BUS_NR 2
static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np)
{
struct regmap *regmap_sfr;
u8 bus_id;
const char *parent_names[2];
struct device_node *i2s_mux_np;
struct clk_hw *hw;
int ret;
regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
if (IS_ERR(regmap_sfr))
return;
for_each_child_of_node(np, i2s_mux_np) {
if (of_property_read_u8(i2s_mux_np, "reg", &bus_id))
continue;
if (bus_id > I2S_BUS_NR)
continue;
ret = of_clk_parent_fill(i2s_mux_np, parent_names, 2);
if (ret != 2)
continue;
hw = at91_clk_i2s_mux_register(regmap_sfr, i2s_mux_np->name,
parent_names, 2, bus_id);
if (IS_ERR(hw))
continue;
of_clk_add_hw_provider(i2s_mux_np, of_clk_hw_simple_get, hw);
}
}
CLK_OF_DECLARE(sama5d2_clk_i2s_mux, "atmel,sama5d2-clk-i2s-mux",
of_sama5d2_clk_i2s_mux_setup);
#endif /* CONFIG_HAVE_AT91_I2S_MUX_CLK */
static void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np)
{
struct clk_hw *hw;
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);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91_clk_register_main_osc(regmap, name, parent_name, bypass);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc",
of_at91rm9200_clk_main_osc_setup);
static void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np)
{
struct clk_hw *hw;
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);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91_clk_register_main_rc_osc(regmap, name, frequency, accuracy);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91sam9x5_clk_main_rc_osc, "atmel,at91sam9x5-clk-main-rc-osc",
of_at91sam9x5_clk_main_rc_osc_setup);
static void __init of_at91rm9200_clk_main_setup(struct device_node *np)
{
struct clk_hw *hw;
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);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91_clk_register_rm9200_main(regmap, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main",
of_at91rm9200_clk_main_setup);
static void __init of_at91sam9x5_clk_main_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *parent_names[2];
unsigned int num_parents;
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);
hw = at91_clk_register_sam9x5_main(regmap, name, parent_names,
num_parents);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main",
of_at91sam9x5_clk_main_setup);
static struct clk_master_characteristics * __init
of_at91_clk_master_get_characteristics(struct device_node *np)
{
struct clk_master_characteristics *characteristics;
characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
if (!characteristics)
return NULL;
if (of_at91_get_clk_range(np, "atmel,clk-output-range", &characteristics->output))
goto out_free_characteristics;
of_property_read_u32_array(np, "atmel,clk-divisors",
characteristics->divisors, 4);
characteristics->have_div3_pres =
of_property_read_bool(np, "atmel,master-clk-have-div3-pres");
return characteristics;
out_free_characteristics:
kfree(characteristics);
return NULL;
}
static void __init
of_at91_clk_master_setup(struct device_node *np,
const struct clk_master_layout *layout)
{
struct clk_hw *hw;
unsigned int num_parents;
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)
return;
of_clk_parent_fill(np, parent_names, num_parents);
of_property_read_string(np, "clock-output-names", &name);
characteristics = of_at91_clk_master_get_characteristics(np);
if (!characteristics)
return;
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91_clk_register_master(regmap, name, num_parents,
parent_names, layout,
characteristics);
if (IS_ERR(hw))
goto out_free_characteristics;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
return;
out_free_characteristics:
kfree(characteristics);
}
static void __init of_at91rm9200_clk_master_setup(struct device_node *np)
{
of_at91_clk_master_setup(np, &at91rm9200_master_layout);
}
CLK_OF_DECLARE(at91rm9200_clk_master, "atmel,at91rm9200-clk-master",
of_at91rm9200_clk_master_setup);
static void __init of_at91sam9x5_clk_master_setup(struct device_node *np)
{
of_at91_clk_master_setup(np, &at91sam9x5_master_layout);
}
CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master",
of_at91sam9x5_clk_master_setup);
static void __init
of_at91_clk_periph_setup(struct device_node *np, u8 type)
{
int num;
u32 id;
struct clk_hw *hw;
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)
return;
num = of_get_child_count(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, periphclknp) {
if (of_property_read_u32(periphclknp, "reg", &id))
continue;
if (id >= PERIPHERAL_MAX)
continue;
if (of_property_read_string(np, "clock-output-names", &name))
name = periphclknp->name;
if (type == PERIPHERAL_AT91RM9200) {
hw = at91_clk_register_peripheral(regmap, name,
parent_name, id);
} else {
struct clk_range range = CLK_RANGE(0, 0);
of_at91_get_clk_range(periphclknp,
"atmel,clk-output-range",
&range);
hw = at91_clk_register_sam9x5_peripheral(regmap,
&pmc_pcr_lock,
name,
parent_name,
id, &range);
}
if (IS_ERR(hw))
continue;
of_clk_add_hw_provider(periphclknp, of_clk_hw_simple_get, hw);
}
}
static void __init of_at91rm9200_clk_periph_setup(struct device_node *np)
{
of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200);
}
CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral",
of_at91rm9200_clk_periph_setup);
static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np)
{
of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5);
}
CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral",
of_at91sam9x5_clk_periph_setup);
static struct clk_pll_characteristics * __init
of_at91_clk_pll_get_characteristics(struct device_node *np)
{
int i;
int offset;
u32 tmp;
int num_output;
u32 num_cells;
struct clk_range input;
struct clk_range *output;
u8 *out = NULL;
u16 *icpll = NULL;
struct clk_pll_characteristics *characteristics;
if (of_at91_get_clk_range(np, "atmel,clk-input-range", &input))
return NULL;
if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells",
&num_cells))
return NULL;
if (num_cells < 2 || num_cells > 4)
return NULL;
if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp))
return NULL;
num_output = tmp / (sizeof(u32) * num_cells);
characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
if (!characteristics)
return NULL;
output = kcalloc(num_output, sizeof(*output), GFP_KERNEL);
if (!output)
goto out_free_characteristics;
if (num_cells > 2) {
out = kcalloc(num_output, sizeof(*out), GFP_KERNEL);
if (!out)
goto out_free_output;
}
if (num_cells > 3) {
icpll = kcalloc(num_output, sizeof(*icpll), GFP_KERNEL);
if (!icpll)
goto out_free_output;
}
for (i = 0; i < num_output; i++) {
offset = i * num_cells;
if (of_property_read_u32_index(np,
"atmel,pll-clk-output-ranges",
offset, &tmp))
goto out_free_output;
output[i].min = tmp;
if (of_property_read_u32_index(np,
"atmel,pll-clk-output-ranges",
offset + 1, &tmp))
goto out_free_output;
output[i].max = tmp;
if (num_cells == 2)
continue;
if (of_property_read_u32_index(np,
"atmel,pll-clk-output-ranges",
offset + 2, &tmp))
goto out_free_output;
out[i] = tmp;
if (num_cells == 3)
continue;
if (of_property_read_u32_index(np,
"atmel,pll-clk-output-ranges",
offset + 3, &tmp))
goto out_free_output;
icpll[i] = tmp;
}
characteristics->input = input;
characteristics->num_output = num_output;
characteristics->output = output;
characteristics->out = out;
characteristics->icpll = icpll;
return characteristics;
out_free_output:
kfree(icpll);
kfree(out);
kfree(output);
out_free_characteristics:
kfree(characteristics);
return NULL;
}
static void __init
of_at91_clk_pll_setup(struct device_node *np,
const struct clk_pll_layout *layout)
{
u32 id;
struct clk_hw *hw;
struct regmap *regmap;
const char *parent_name;
const char *name = np->name;
struct clk_pll_characteristics *characteristics;
if (of_property_read_u32(np, "reg", &id))
return;
parent_name = of_clk_get_parent_name(np, 0);
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;
hw = at91_clk_register_pll(regmap, name, parent_name, id, layout,
characteristics);
if (IS_ERR(hw))
goto out_free_characteristics;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
return;
out_free_characteristics:
kfree(characteristics);
}
static void __init of_at91rm9200_clk_pll_setup(struct device_node *np)
{
of_at91_clk_pll_setup(np, &at91rm9200_pll_layout);
}
CLK_OF_DECLARE(at91rm9200_clk_pll, "atmel,at91rm9200-clk-pll",
of_at91rm9200_clk_pll_setup);
static void __init of_at91sam9g45_clk_pll_setup(struct device_node *np)
{
of_at91_clk_pll_setup(np, &at91sam9g45_pll_layout);
}
CLK_OF_DECLARE(at91sam9g45_clk_pll, "atmel,at91sam9g45-clk-pll",
of_at91sam9g45_clk_pll_setup);
static void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np)
{
of_at91_clk_pll_setup(np, &at91sam9g20_pllb_layout);
}
CLK_OF_DECLARE(at91sam9g20_clk_pllb, "atmel,at91sam9g20-clk-pllb",
of_at91sam9g20_clk_pllb_setup);
static void __init of_sama5d3_clk_pll_setup(struct device_node *np)
{
of_at91_clk_pll_setup(np, &sama5d3_pll_layout);
}
CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll",
of_sama5d3_clk_pll_setup);
static void __init
of_at91sam9x5_clk_plldiv_setup(struct device_node *np)
{
struct clk_hw *hw;
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);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91_clk_register_plldiv(regmap, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv",
of_at91sam9x5_clk_plldiv_setup);
static void __init
of_at91_clk_prog_setup(struct device_node *np,
const struct clk_programmable_layout *layout)
{
int num;
u32 id;
struct clk_hw *hw;
unsigned int num_parents;
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)
return;
of_clk_parent_fill(np, parent_names, num_parents);
num = of_get_child_count(np);
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;
if (of_property_read_string(np, "clock-output-names", &name))
name = progclknp->name;
hw = at91_clk_register_programmable(regmap, name,
parent_names, num_parents,
id, layout);
if (IS_ERR(hw))
continue;
of_clk_add_hw_provider(progclknp, of_clk_hw_simple_get, hw);
}
}
static void __init of_at91rm9200_clk_prog_setup(struct device_node *np)
{
of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout);
}
CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable",
of_at91rm9200_clk_prog_setup);
static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np)
{
of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout);
}
CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable",
of_at91sam9g45_clk_prog_setup);
static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np)
{
of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout);
}
CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable",
of_at91sam9x5_clk_prog_setup);
static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *parent_names[2];
unsigned 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);
hw = at91_clk_register_sam9260_slow(regmap, name, parent_names,
num_parents);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
of_at91sam9260_clk_slow_setup);
#ifdef CONFIG_HAVE_AT91_SMD
#define SMD_SOURCE_MAX 2
static void __init of_at91sam9x5_clk_smd_setup(struct device_node *np)
{
struct clk_hw *hw;
unsigned 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)
return;
of_clk_parent_fill(np, parent_names, num_parents);
of_property_read_string(np, "clock-output-names", &name);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91sam9x5_clk_register_smd(regmap, name, parent_names,
num_parents);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd",
of_at91sam9x5_clk_smd_setup);
#endif /* CONFIG_HAVE_AT91_SMD */
static void __init of_at91rm9200_clk_sys_setup(struct device_node *np)
{
int num;
u32 id;
struct clk_hw *hw;
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;
if (of_property_read_string(np, "clock-output-names", &name))
name = sysclknp->name;
parent_name = of_clk_get_parent_name(sysclknp, 0);
hw = at91_clk_register_system(regmap, name, parent_name, id);
if (IS_ERR(hw))
continue;
of_clk_add_hw_provider(sysclknp, of_clk_hw_simple_get, hw);
}
}
CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system",
of_at91rm9200_clk_sys_setup);
#ifdef CONFIG_HAVE_AT91_USB_CLK
#define USB_SOURCE_MAX 2
static void __init of_at91sam9x5_clk_usb_setup(struct device_node *np)
{
struct clk_hw *hw;
unsigned 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)
return;
of_clk_parent_fill(np, parent_names, num_parents);
of_property_read_string(np, "clock-output-names", &name);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91sam9x5_clk_register_usb(regmap, name, parent_names,
num_parents);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb",
of_at91sam9x5_clk_usb_setup);
static void __init of_at91sam9n12_clk_usb_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *parent_name;
const char *name = np->name;
struct regmap *regmap;
parent_name = of_clk_get_parent_name(np, 0);
if (!parent_name)
return;
of_property_read_string(np, "clock-output-names", &name);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91sam9n12_clk_register_usb(regmap, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb",
of_at91sam9n12_clk_usb_setup);
static void __init of_at91rm9200_clk_usb_setup(struct device_node *np)
{
struct clk_hw *hw;
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)
return;
of_property_read_u32_array(np, "atmel,clk-divisors", divisors, 4);
if (!divisors[0])
return;
of_property_read_string(np, "clock-output-names", &name);
regmap = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap))
return;
hw = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb",
of_at91rm9200_clk_usb_setup);
#endif /* CONFIG_HAVE_AT91_USB_CLK */
#ifdef CONFIG_HAVE_AT91_UTMI
static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
{
struct clk_hw *hw;
const char *parent_name;
const char *name = np->name;
struct regmap *regmap_pmc, *regmap_sfr;
parent_name = of_clk_get_parent_name(np, 0);
of_property_read_string(np, "clock-output-names", &name);
regmap_pmc = syscon_node_to_regmap(of_get_parent(np));
if (IS_ERR(regmap_pmc))
return;
/*
* If the device supports different mainck rates, this value has to be
* set in the UTMI Clock Trimming register.
* - 9x5: mainck supports several rates but it is indicated that a
* 12 MHz is needed in case of USB.
* - sama5d3 and sama5d2: mainck supports several rates. Configuring
* the FREQ field of the UTMI Clock Trimming register is mandatory.
* - sama5d4: mainck is at 12 MHz.
*
* We only need to retrieve sama5d3 or sama5d2 sfr regmap.
*/
regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d3-sfr");
if (IS_ERR(regmap_sfr)) {
regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
if (IS_ERR(regmap_sfr))
regmap_sfr = NULL;
}
hw = at91_clk_register_utmi(regmap_pmc, regmap_sfr, name, parent_name);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi",
of_at91sam9x5_clk_utmi_setup);
#endif /* CONFIG_HAVE_AT91_UTMI */

View File

@@ -19,6 +19,8 @@
#include <asm/proc-fns.h>
#include <dt-bindings/clock/at91.h>
#include "pmc.h"
#define PMC_MAX_IDS 128
@@ -47,6 +49,82 @@ int of_at91_get_clk_range(struct device_node *np, const char *propname,
}
EXPORT_SYMBOL_GPL(of_at91_get_clk_range);
struct clk_hw *of_clk_hw_pmc_get(struct of_phandle_args *clkspec, void *data)
{
unsigned int type = clkspec->args[0];
unsigned int idx = clkspec->args[1];
struct pmc_data *pmc_data = data;
switch (type) {
case PMC_TYPE_CORE:
if (idx < pmc_data->ncore)
return pmc_data->chws[idx];
break;
case PMC_TYPE_SYSTEM:
if (idx < pmc_data->nsystem)
return pmc_data->shws[idx];
break;
case PMC_TYPE_PERIPHERAL:
if (idx < pmc_data->nperiph)
return pmc_data->phws[idx];
break;
case PMC_TYPE_GCK:
if (idx < pmc_data->ngck)
return pmc_data->ghws[idx];
break;
default:
break;
}
pr_err("%s: invalid type (%u) or index (%u)\n", __func__, type, idx);
return ERR_PTR(-EINVAL);
}
void pmc_data_free(struct pmc_data *pmc_data)
{
kfree(pmc_data->chws);
kfree(pmc_data->shws);
kfree(pmc_data->phws);
kfree(pmc_data->ghws);
}
struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
unsigned int nperiph, unsigned int ngck)
{
struct pmc_data *pmc_data = kzalloc(sizeof(*pmc_data), GFP_KERNEL);
if (!pmc_data)
return NULL;
pmc_data->ncore = ncore;
pmc_data->chws = kcalloc(ncore, sizeof(struct clk_hw *), GFP_KERNEL);
if (!pmc_data->chws)
goto err;
pmc_data->nsystem = nsystem;
pmc_data->shws = kcalloc(nsystem, sizeof(struct clk_hw *), GFP_KERNEL);
if (!pmc_data->shws)
goto err;
pmc_data->nperiph = nperiph;
pmc_data->phws = kcalloc(nperiph, sizeof(struct clk_hw *), GFP_KERNEL);
if (!pmc_data->phws)
goto err;
pmc_data->ngck = ngck;
pmc_data->ghws = kcalloc(ngck, sizeof(struct clk_hw *), GFP_KERNEL);
if (!pmc_data->ghws)
goto err;
return pmc_data;
err:
pmc_data_free(pmc_data);
return NULL;
}
#ifdef CONFIG_PM
static struct regmap *pmcreg;

View File

@@ -19,6 +19,17 @@
extern spinlock_t pmc_pcr_lock;
struct pmc_data {
unsigned int ncore;
struct clk_hw **chws;
unsigned int nsystem;
struct clk_hw **shws;
unsigned int nperiph;
struct clk_hw **phws;
unsigned int ngck;
struct clk_hw **ghws;
};
struct clk_range {
unsigned long min;
unsigned long max;
@@ -26,9 +37,157 @@ struct clk_range {
#define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,}
struct clk_master_layout {
u32 mask;
u8 pres_shift;
};
extern const struct clk_master_layout at91rm9200_master_layout;
extern const struct clk_master_layout at91sam9x5_master_layout;
struct clk_master_characteristics {
struct clk_range output;
u32 divisors[4];
u8 have_div3_pres;
};
struct clk_pll_layout {
u32 pllr_mask;
u16 mul_mask;
u8 mul_shift;
};
extern const struct clk_pll_layout at91rm9200_pll_layout;
extern const struct clk_pll_layout at91sam9g45_pll_layout;
extern const struct clk_pll_layout at91sam9g20_pllb_layout;
extern const struct clk_pll_layout sama5d3_pll_layout;
struct clk_pll_characteristics {
struct clk_range input;
int num_output;
struct clk_range *output;
u16 *icpll;
u8 *out;
};
struct clk_programmable_layout {
u8 pres_shift;
u8 css_mask;
u8 have_slck_mck;
};
extern const struct clk_programmable_layout at91rm9200_programmable_layout;
extern const struct clk_programmable_layout at91sam9g45_programmable_layout;
extern const struct clk_programmable_layout at91sam9x5_programmable_layout;
#define ndck(a, s) (a[s - 1].id + 1)
#define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1)
struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
unsigned int nperiph, unsigned int ngck);
void pmc_data_free(struct pmc_data *pmc_data);
int of_at91_get_clk_range(struct device_node *np, const char *propname,
struct clk_range *range);
struct clk_hw *of_clk_hw_pmc_get(struct of_phandle_args *clkspec, void *data);
struct clk_hw * __init
at91_clk_register_audio_pll_frac(struct regmap *regmap, const char *name,
const char *parent_name);
struct clk_hw * __init
at91_clk_register_audio_pll_pad(struct regmap *regmap, const char *name,
const char *parent_name);
struct clk_hw * __init
at91_clk_register_audio_pll_pmc(struct regmap *regmap, const char *name,
const char *parent_name);
struct clk_hw * __init
at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
const char *name, const char **parent_names,
u8 num_parents, u8 id, bool pll_audio,
const struct clk_range *range);
struct clk_hw * __init
at91_clk_register_h32mx(struct regmap *regmap, const char *name,
const char *parent_name);
struct clk_hw * __init
at91_clk_i2s_mux_register(struct regmap *regmap, const char *name,
const char * const *parent_names,
unsigned int num_parents, u8 bus_id);
struct clk_hw * __init
at91_clk_register_main_rc_osc(struct regmap *regmap, const char *name,
u32 frequency, u32 accuracy);
struct clk_hw * __init
at91_clk_register_main_osc(struct regmap *regmap, const char *name,
const char *parent_name, bool bypass);
struct clk_hw * __init
at91_clk_register_rm9200_main(struct regmap *regmap,
const char *name,
const char *parent_name);
struct clk_hw * __init
at91_clk_register_sam9x5_main(struct regmap *regmap, const char *name,
const char **parent_names, int num_parents);
struct clk_hw * __init
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);
struct clk_hw * __init
at91_clk_register_peripheral(struct regmap *regmap, const char *name,
const char *parent_name, u32 id);
struct clk_hw * __init
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_hw * __init
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);
struct clk_hw * __init
at91_clk_register_plldiv(struct regmap *regmap, const char *name,
const char *parent_name);
struct clk_hw * __init
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);
struct clk_hw * __init
at91_clk_register_sam9260_slow(struct regmap *regmap,
const char *name,
const char **parent_names,
int num_parents);
struct clk_hw * __init
at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents);
struct clk_hw * __init
at91_clk_register_system(struct regmap *regmap, const char *name,
const char *parent_name, u8 id);
struct clk_hw * __init
at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents);
struct clk_hw * __init
at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,
const char *parent_name);
struct clk_hw * __init
at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,
const char *parent_name, const u32 *divisors);
struct clk_hw * __init
at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
const char *name, const char *parent_name);
#ifdef CONFIG_PM
void pmc_register_id(u8 id);
void pmc_register_pck(u8 pck);

336
drivers/clk/at91/sama5d2.c Normal file
View File

@@ -0,0 +1,336 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
#include <dt-bindings/clock/at91.h>
#include "pmc.h"
static const struct clk_master_characteristics mck_characteristics = {
.output = { .min = 124000000, .max = 166000000 },
.divisors = { 1, 2, 4, 3 },
};
static u8 plla_out[] = { 0 };
static u16 plla_icpll[] = { 0 };
static struct clk_range plla_outputs[] = {
{ .min = 600000000, .max = 1200000000 },
};
static const struct clk_pll_characteristics plla_characteristics = {
.input = { .min = 12000000, .max = 12000000 },
.num_output = ARRAY_SIZE(plla_outputs),
.output = plla_outputs,
.icpll = plla_icpll,
.out = plla_out,
};
static const struct {
char *n;
char *p;
u8 id;
} sama5d2_systemck[] = {
{ .n = "ddrck", .p = "masterck", .id = 2 },
{ .n = "lcdck", .p = "masterck", .id = 3 },
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "udpck", .p = "usbck", .id = 7 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
{ .n = "pck2", .p = "prog2", .id = 10 },
{ .n = "iscck", .p = "masterck", .id = 18 },
};
static const struct {
char *n;
u8 id;
struct clk_range r;
} sama5d2_periph32ck[] = {
{ .n = "macb0_clk", .id = 5, .r = { .min = 0, .max = 83000000 }, },
{ .n = "tdes_clk", .id = 11, .r = { .min = 0, .max = 83000000 }, },
{ .n = "matrix1_clk", .id = 14, },
{ .n = "hsmc_clk", .id = 17, },
{ .n = "pioA_clk", .id = 18, .r = { .min = 0, .max = 83000000 }, },
{ .n = "flx0_clk", .id = 19, .r = { .min = 0, .max = 83000000 }, },
{ .n = "flx1_clk", .id = 20, .r = { .min = 0, .max = 83000000 }, },
{ .n = "flx2_clk", .id = 21, .r = { .min = 0, .max = 83000000 }, },
{ .n = "flx3_clk", .id = 22, .r = { .min = 0, .max = 83000000 }, },
{ .n = "flx4_clk", .id = 23, .r = { .min = 0, .max = 83000000 }, },
{ .n = "uart0_clk", .id = 24, .r = { .min = 0, .max = 83000000 }, },
{ .n = "uart1_clk", .id = 25, .r = { .min = 0, .max = 83000000 }, },
{ .n = "uart2_clk", .id = 26, .r = { .min = 0, .max = 83000000 }, },
{ .n = "uart3_clk", .id = 27, .r = { .min = 0, .max = 83000000 }, },
{ .n = "uart4_clk", .id = 28, .r = { .min = 0, .max = 83000000 }, },
{ .n = "twi0_clk", .id = 29, .r = { .min = 0, .max = 83000000 }, },
{ .n = "twi1_clk", .id = 30, .r = { .min = 0, .max = 83000000 }, },
{ .n = "spi0_clk", .id = 33, .r = { .min = 0, .max = 83000000 }, },
{ .n = "spi1_clk", .id = 34, .r = { .min = 0, .max = 83000000 }, },
{ .n = "tcb0_clk", .id = 35, .r = { .min = 0, .max = 83000000 }, },
{ .n = "tcb1_clk", .id = 36, .r = { .min = 0, .max = 83000000 }, },
{ .n = "pwm_clk", .id = 38, .r = { .min = 0, .max = 83000000 }, },
{ .n = "adc_clk", .id = 40, .r = { .min = 0, .max = 83000000 }, },
{ .n = "uhphs_clk", .id = 41, .r = { .min = 0, .max = 83000000 }, },
{ .n = "udphs_clk", .id = 42, .r = { .min = 0, .max = 83000000 }, },
{ .n = "ssc0_clk", .id = 43, .r = { .min = 0, .max = 83000000 }, },
{ .n = "ssc1_clk", .id = 44, .r = { .min = 0, .max = 83000000 }, },
{ .n = "trng_clk", .id = 47, .r = { .min = 0, .max = 83000000 }, },
{ .n = "pdmic_clk", .id = 48, .r = { .min = 0, .max = 83000000 }, },
{ .n = "securam_clk", .id = 51, },
{ .n = "i2s0_clk", .id = 54, .r = { .min = 0, .max = 83000000 }, },
{ .n = "i2s1_clk", .id = 55, .r = { .min = 0, .max = 83000000 }, },
{ .n = "can0_clk", .id = 56, .r = { .min = 0, .max = 83000000 }, },
{ .n = "can1_clk", .id = 57, .r = { .min = 0, .max = 83000000 }, },
{ .n = "classd_clk", .id = 59, .r = { .min = 0, .max = 83000000 }, },
};
static const struct {
char *n;
u8 id;
} sama5d2_periphck[] = {
{ .n = "dma0_clk", .id = 6, },
{ .n = "dma1_clk", .id = 7, },
{ .n = "aes_clk", .id = 9, },
{ .n = "aesb_clk", .id = 10, },
{ .n = "sha_clk", .id = 12, },
{ .n = "mpddr_clk", .id = 13, },
{ .n = "matrix0_clk", .id = 15, },
{ .n = "sdmmc0_hclk", .id = 31, },
{ .n = "sdmmc1_hclk", .id = 32, },
{ .n = "lcdc_clk", .id = 45, },
{ .n = "isc_clk", .id = 46, },
{ .n = "qspi0_clk", .id = 52, },
{ .n = "qspi1_clk", .id = 53, },
};
static const struct {
char *n;
u8 id;
struct clk_range r;
bool pll;
} sama5d2_gck[] = {
{ .n = "sdmmc0_gclk", .id = 31, },
{ .n = "sdmmc1_gclk", .id = 32, },
{ .n = "tcb0_gclk", .id = 35, .r = { .min = 0, .max = 83000000 }, },
{ .n = "tcb1_gclk", .id = 36, .r = { .min = 0, .max = 83000000 }, },
{ .n = "pwm_gclk", .id = 38, .r = { .min = 0, .max = 83000000 }, },
{ .n = "isc_gclk", .id = 46, },
{ .n = "pdmic_gclk", .id = 48, },
{ .n = "i2s0_gclk", .id = 54, .pll = true },
{ .n = "i2s1_gclk", .id = 55, .pll = true },
{ .n = "can0_gclk", .id = 56, .r = { .min = 0, .max = 80000000 }, },
{ .n = "can1_gclk", .id = 57, .r = { .min = 0, .max = 80000000 }, },
{ .n = "classd_gclk", .id = 59, .r = { .min = 0, .max = 100000000 },
.pll = true },
};
static void __init sama5d2_pmc_setup(struct device_node *np)
{
struct clk_range range = CLK_RANGE(0, 0);
const char *slck_name, *mainxtal_name;
struct pmc_data *sama5d2_pmc;
const char *parent_names[6];
struct regmap *regmap, *regmap_sfr;
struct clk_hw *hw;
int i;
bool bypass;
i = of_property_match_string(np, "clock-names", "slow_clk");
if (i < 0)
return;
slck_name = of_clk_get_parent_name(np, i);
i = of_property_match_string(np, "clock-names", "main_xtal");
if (i < 0)
return;
mainxtal_name = of_clk_get_parent_name(np, i);
regmap = syscon_node_to_regmap(np);
if (IS_ERR(regmap))
return;
sama5d2_pmc = pmc_data_allocate(PMC_I2S1_MUX + 1,
nck(sama5d2_systemck),
nck(sama5d2_periph32ck),
nck(sama5d2_gck));
if (!sama5d2_pmc)
return;
hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
100000000);
if (IS_ERR(hw))
goto err_free;
bypass = of_property_read_bool(np, "atmel,osc-bypass");
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
bypass);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = "main_rc_osc";
parent_names[1] = "main_osc";
hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2);
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->chws[PMC_MAIN] = hw;
hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
&sama5d3_pll_layout, &plla_characteristics);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack");
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_audio_pll_frac(regmap, "audiopll_fracck",
"mainck");
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_audio_pll_pad(regmap, "audiopll_padck",
"audiopll_fracck");
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_audio_pll_pmc(regmap, "audiopll_pmcck",
"audiopll_fracck");
if (IS_ERR(hw))
goto err_free;
regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
if (IS_ERR(regmap_sfr))
regmap_sfr = NULL;
hw = at91_clk_register_utmi(regmap, regmap_sfr, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->chws[PMC_UTMI] = hw;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
parent_names[3] = "utmick";
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
&at91sam9x5_master_layout,
&mck_characteristics);
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->chws[PMC_MCK] = hw;
hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck");
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->chws[PMC_MCK2] = hw;
parent_names[0] = "plladivck";
parent_names[1] = "utmick";
hw = at91sam9x5_clk_register_usb(regmap, "usbck", parent_names, 2);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
parent_names[3] = "utmick";
parent_names[4] = "mck";
for (i = 0; i < 3; i++) {
char name[6];
snprintf(name, sizeof(name), "prog%d", i);
hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i,
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
}
for (i = 0; i < ARRAY_SIZE(sama5d2_systemck); i++) {
hw = at91_clk_register_system(regmap, sama5d2_systemck[i].n,
sama5d2_systemck[i].p,
sama5d2_systemck[i].id);
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->shws[sama5d2_systemck[i].id] = hw;
}
for (i = 0; i < ARRAY_SIZE(sama5d2_periphck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
sama5d2_periphck[i].n,
"masterck",
sama5d2_periphck[i].id,
&range);
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->phws[sama5d2_periphck[i].id] = hw;
}
for (i = 0; i < ARRAY_SIZE(sama5d2_periph32ck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
sama5d2_periph32ck[i].n,
"h32mxck",
sama5d2_periph32ck[i].id,
&sama5d2_periph32ck[i].r);
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->phws[sama5d2_periph32ck[i].id] = hw;
}
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
parent_names[3] = "utmick";
parent_names[4] = "mck";
parent_names[5] = "audiopll_pmcck";
for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) {
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
sama5d2_gck[i].n,
parent_names, 6,
sama5d2_gck[i].id,
sama5d2_gck[i].pll,
&sama5d2_gck[i].r);
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->ghws[sama5d2_gck[i].id] = hw;
}
if (regmap_sfr) {
parent_names[0] = "i2s0_clk";
parent_names[1] = "i2s0_gclk";
hw = at91_clk_i2s_mux_register(regmap_sfr, "i2s0_muxclk",
parent_names, 2, 0);
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->chws[PMC_I2S0_MUX] = hw;
parent_names[0] = "i2s1_clk";
parent_names[1] = "i2s1_gclk";
hw = at91_clk_i2s_mux_register(regmap_sfr, "i2s1_muxclk",
parent_names, 2, 1);
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->chws[PMC_I2S1_MUX] = hw;
}
of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama5d2_pmc);
return;
err_free:
pmc_data_free(sama5d2_pmc);
}
CLK_OF_DECLARE_DRIVER(sama5d2_pmc, "atmel,sama5d2-pmc", sama5d2_pmc_setup);

264
drivers/clk/at91/sama5d4.c Normal file
View File

@@ -0,0 +1,264 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
#include <dt-bindings/clock/at91.h>
#include "pmc.h"
static const struct clk_master_characteristics mck_characteristics = {
.output = { .min = 125000000, .max = 200000000 },
.divisors = { 1, 2, 4, 3 },
};
static u8 plla_out[] = { 0 };
static u16 plla_icpll[] = { 0 };
static struct clk_range plla_outputs[] = {
{ .min = 600000000, .max = 1200000000 },
};
static const struct clk_pll_characteristics plla_characteristics = {
.input = { .min = 12000000, .max = 12000000 },
.num_output = ARRAY_SIZE(plla_outputs),
.output = plla_outputs,
.icpll = plla_icpll,
.out = plla_out,
};
static const struct {
char *n;
char *p;
u8 id;
} sama5d4_systemck[] = {
{ .n = "ddrck", .p = "masterck", .id = 2 },
{ .n = "lcdck", .p = "masterck", .id = 3 },
{ .n = "smdck", .p = "smdclk", .id = 4 },
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "udpck", .p = "usbck", .id = 7 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
{ .n = "pck2", .p = "prog2", .id = 10 },
};
static const struct {
char *n;
u8 id;
} sama5d4_periph32ck[] = {
{ .n = "pioD_clk", .id = 5 },
{ .n = "usart0_clk", .id = 6 },
{ .n = "usart1_clk", .id = 7 },
{ .n = "icm_clk", .id = 9 },
{ .n = "aes_clk", .id = 12 },
{ .n = "tdes_clk", .id = 14 },
{ .n = "sha_clk", .id = 15 },
{ .n = "matrix1_clk", .id = 17 },
{ .n = "hsmc_clk", .id = 22 },
{ .n = "pioA_clk", .id = 23 },
{ .n = "pioB_clk", .id = 24 },
{ .n = "pioC_clk", .id = 25 },
{ .n = "pioE_clk", .id = 26 },
{ .n = "uart0_clk", .id = 27 },
{ .n = "uart1_clk", .id = 28 },
{ .n = "usart2_clk", .id = 29 },
{ .n = "usart3_clk", .id = 30 },
{ .n = "usart4_clk", .id = 31 },
{ .n = "twi0_clk", .id = 32 },
{ .n = "twi1_clk", .id = 33 },
{ .n = "twi2_clk", .id = 34 },
{ .n = "mci0_clk", .id = 35 },
{ .n = "mci1_clk", .id = 36 },
{ .n = "spi0_clk", .id = 37 },
{ .n = "spi1_clk", .id = 38 },
{ .n = "spi2_clk", .id = 39 },
{ .n = "tcb0_clk", .id = 40 },
{ .n = "tcb1_clk", .id = 41 },
{ .n = "tcb2_clk", .id = 42 },
{ .n = "pwm_clk", .id = 43 },
{ .n = "adc_clk", .id = 44 },
{ .n = "dbgu_clk", .id = 45 },
{ .n = "uhphs_clk", .id = 46 },
{ .n = "udphs_clk", .id = 47 },
{ .n = "ssc0_clk", .id = 48 },
{ .n = "ssc1_clk", .id = 49 },
{ .n = "trng_clk", .id = 53 },
{ .n = "macb0_clk", .id = 54 },
{ .n = "macb1_clk", .id = 55 },
{ .n = "fuse_clk", .id = 57 },
{ .n = "securam_clk", .id = 59 },
{ .n = "smd_clk", .id = 61 },
{ .n = "twi3_clk", .id = 62 },
{ .n = "catb_clk", .id = 63 },
};
static const struct {
char *n;
u8 id;
} sama5d4_periphck[] = {
{ .n = "dma0_clk", .id = 8 },
{ .n = "cpkcc_clk", .id = 10 },
{ .n = "aesb_clk", .id = 13 },
{ .n = "mpddr_clk", .id = 16 },
{ .n = "matrix0_clk", .id = 18 },
{ .n = "vdec_clk", .id = 19 },
{ .n = "dma1_clk", .id = 50 },
{ .n = "lcdc_clk", .id = 51 },
{ .n = "isi_clk", .id = 52 },
};
static void __init sama5d4_pmc_setup(struct device_node *np)
{
struct clk_range range = CLK_RANGE(0, 0);
const char *slck_name, *mainxtal_name;
struct pmc_data *sama5d4_pmc;
const char *parent_names[5];
struct regmap *regmap;
struct clk_hw *hw;
int i;
bool bypass;
i = of_property_match_string(np, "clock-names", "slow_clk");
if (i < 0)
return;
slck_name = of_clk_get_parent_name(np, i);
i = of_property_match_string(np, "clock-names", "main_xtal");
if (i < 0)
return;
mainxtal_name = of_clk_get_parent_name(np, i);
regmap = syscon_node_to_regmap(np);
if (IS_ERR(regmap))
return;
sama5d4_pmc = pmc_data_allocate(PMC_MCK2 + 1,
nck(sama5d4_systemck),
nck(sama5d4_periph32ck), 0);
if (!sama5d4_pmc)
return;
hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
100000000);
if (IS_ERR(hw))
goto err_free;
bypass = of_property_read_bool(np, "atmel,osc-bypass");
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
bypass);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = "main_rc_osc";
parent_names[1] = "main_osc";
hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
&sama5d3_pll_layout, &plla_characteristics);
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack");
if (IS_ERR(hw))
goto err_free;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
sama5d4_pmc->chws[PMC_UTMI] = hw;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
parent_names[3] = "utmick";
hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
&at91sam9x5_master_layout,
&mck_characteristics);
if (IS_ERR(hw))
goto err_free;
sama5d4_pmc->chws[PMC_MCK] = hw;
hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck");
if (IS_ERR(hw))
goto err_free;
sama5d4_pmc->chws[PMC_MCK2] = hw;
parent_names[0] = "plladivck";
parent_names[1] = "utmick";
hw = at91sam9x5_clk_register_usb(regmap, "usbck", parent_names, 2);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = "plladivck";
parent_names[1] = "utmick";
hw = at91sam9x5_clk_register_smd(regmap, "smdclk", parent_names, 2);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
parent_names[3] = "utmick";
parent_names[4] = "mck";
for (i = 0; i < 3; i++) {
char name[6];
snprintf(name, sizeof(name), "prog%d", i);
hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i,
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
}
for (i = 0; i < ARRAY_SIZE(sama5d4_systemck); i++) {
hw = at91_clk_register_system(regmap, sama5d4_systemck[i].n,
sama5d4_systemck[i].p,
sama5d4_systemck[i].id);
if (IS_ERR(hw))
goto err_free;
sama5d4_pmc->shws[sama5d4_systemck[i].id] = hw;
}
for (i = 0; i < ARRAY_SIZE(sama5d4_periphck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
sama5d4_periphck[i].n,
"masterck",
sama5d4_periphck[i].id,
&range);
if (IS_ERR(hw))
goto err_free;
sama5d4_pmc->phws[sama5d4_periphck[i].id] = hw;
}
for (i = 0; i < ARRAY_SIZE(sama5d4_periph32ck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
sama5d4_periph32ck[i].n,
"h32mxck",
sama5d4_periph32ck[i].id,
&range);
if (IS_ERR(hw))
goto err_free;
sama5d4_pmc->phws[sama5d4_periph32ck[i].id] = hw;
}
of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama5d4_pmc);
return;
err_free:
pmc_data_free(sama5d4_pmc);
}
CLK_OF_DECLARE_DRIVER(sama5d4_pmc, "atmel,sama5d4-pmc", sama5d4_pmc_setup);

View File

@@ -301,13 +301,13 @@ static void __init of_axs10x_pll_clk_setup(struct device_node *node)
ret = clk_hw_register(NULL, &pll_clk->hw);
if (ret) {
pr_err("failed to register %s clock\n", node->name);
pr_err("failed to register %pOFn clock\n", node);
goto err_unmap_lock;
}
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clk->hw);
if (ret) {
pr_err("failed to add hw provider for %s clock\n", node->name);
pr_err("failed to add hw provider for %pOFn clock\n", node);
goto err_unregister_clk;
}

View File

@@ -808,29 +808,29 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu,
ret = of_address_to_resource(node, 0, &res);
if (ret) {
pr_err("%s: no valid CCU registers found for %s\n", __func__,
node->name);
pr_err("%s: no valid CCU registers found for %pOFn\n", __func__,
node);
goto out_err;
}
range = resource_size(&res);
if (range > (resource_size_t)U32_MAX) {
pr_err("%s: address range too large for %s\n", __func__,
node->name);
pr_err("%s: address range too large for %pOFn\n", __func__,
node);
goto out_err;
}
ccu->range = (u32)range;
if (!ccu_data_valid(ccu)) {
pr_err("%s: ccu data not valid for %s\n", __func__, node->name);
pr_err("%s: ccu data not valid for %pOFn\n", __func__, node);
goto out_err;
}
ccu->base = ioremap(res.start, ccu->range);
if (!ccu->base) {
pr_err("%s: unable to map CCU registers for %s\n", __func__,
node->name);
pr_err("%s: unable to map CCU registers for %pOFn\n", __func__,
node);
goto out_err;
}
ccu->node = of_node_get(node);
@@ -848,16 +848,16 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu,
ret = of_clk_add_hw_provider(node, of_clk_kona_onecell_get, ccu);
if (ret) {
pr_err("%s: error adding ccu %s as provider (%d)\n", __func__,
node->name, ret);
pr_err("%s: error adding ccu %pOFn as provider (%d)\n", __func__,
node, ret);
goto out_err;
}
if (!kona_ccu_init(ccu))
pr_err("Broadcom %s initialization had errors\n", node->name);
pr_err("Broadcom %pOFn initialization had errors\n", node);
return;
out_err:
kona_ccu_teardown(ccu);
pr_err("Broadcom %s setup aborted\n", node->name);
pr_err("Broadcom %pOFn setup aborted\n", node);
}

View File

@@ -281,7 +281,7 @@ static void __init asm9260_acc_init(struct device_node *np)
base = of_io_request_and_map(np, 0, np->name);
if (IS_ERR(base))
panic("%s: unable to map resource", np->name);
panic("%pOFn: unable to map resource", np);
/* register pll */
rate = (ioread32(base + HW_SYSPLLCTRL) & 0xffff) * 1000000;
@@ -292,7 +292,7 @@ static void __init asm9260_acc_init(struct device_node *np)
ref_clk, 0, rate, accuracy);
if (IS_ERR(hw))
panic("%s: can't register REFCLK. Check DT!", np->name);
panic("%pOFn: can't register REFCLK. Check DT!", np);
for (n = 0; n < ARRAY_SIZE(asm9260_mux_clks); n++) {
const struct asm9260_mux_clock *mc = &asm9260_mux_clks[n];

View File

@@ -17,8 +17,65 @@
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/of.h>
#include <linux/slab.h>
static int __must_check of_clk_bulk_get(struct device_node *np, int num_clks,
struct clk_bulk_data *clks)
{
int ret;
int i;
for (i = 0; i < num_clks; i++)
clks[i].clk = NULL;
for (i = 0; i < num_clks; i++) {
clks[i].clk = of_clk_get(np, i);
if (IS_ERR(clks[i].clk)) {
ret = PTR_ERR(clks[i].clk);
pr_err("%pOF: Failed to get clk index: %d ret: %d\n",
np, i, ret);
clks[i].clk = NULL;
goto err;
}
}
return 0;
err:
clk_bulk_put(i, clks);
return ret;
}
static int __must_check of_clk_bulk_get_all(struct device_node *np,
struct clk_bulk_data **clks)
{
struct clk_bulk_data *clk_bulk;
int num_clks;
int ret;
num_clks = of_clk_get_parent_count(np);
if (!num_clks)
return 0;
clk_bulk = kmalloc_array(num_clks, sizeof(*clk_bulk), GFP_KERNEL);
if (!clk_bulk)
return -ENOMEM;
ret = of_clk_bulk_get(np, num_clks, clk_bulk);
if (ret) {
kfree(clk_bulk);
return ret;
}
*clks = clk_bulk;
return num_clks;
}
void clk_bulk_put(int num_clks, struct clk_bulk_data *clks)
{
@@ -59,6 +116,29 @@ err:
}
EXPORT_SYMBOL(clk_bulk_get);
void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks)
{
if (IS_ERR_OR_NULL(clks))
return;
clk_bulk_put(num_clks, clks);
kfree(clks);
}
EXPORT_SYMBOL(clk_bulk_put_all);
int __must_check clk_bulk_get_all(struct device *dev,
struct clk_bulk_data **clks)
{
struct device_node *np = dev_of_node(dev);
if (!np)
return 0;
return of_clk_bulk_get_all(np, clks);
}
EXPORT_SYMBOL(clk_bulk_get_all);
#ifdef CONFIG_HAVE_CLK_PREPARE
/**

View File

@@ -669,8 +669,8 @@ static int cdce925_probe(struct i2c_client *client,
/* Register PLL clocks */
for (i = 0; i < data->chip_info->num_plls; ++i) {
pll_clk_name[i] = kasprintf(GFP_KERNEL, "%s.pll%d",
client->dev.of_node->name, i);
pll_clk_name[i] = kasprintf(GFP_KERNEL, "%pOFn.pll%d",
client->dev.of_node, i);
init.name = pll_clk_name[i];
data->pll[i].chip = data;
data->pll[i].hw.init = &init;
@@ -703,6 +703,7 @@ static int cdce925_probe(struct i2c_client *client,
0x12 + (i*CDCE925_OFFSET_PLL),
0x07, value & 0x07);
}
of_node_put(np_output);
}
/* Register output clock Y1 */
@@ -710,7 +711,7 @@ static int cdce925_probe(struct i2c_client *client,
init.flags = 0;
init.num_parents = 1;
init.parent_names = &parent_name; /* Mux Y1 to input */
init.name = kasprintf(GFP_KERNEL, "%s.Y1", client->dev.of_node->name);
init.name = kasprintf(GFP_KERNEL, "%pOFn.Y1", client->dev.of_node);
data->clk[0].chip = data;
data->clk[0].hw.init = &init;
data->clk[0].index = 0;
@@ -727,8 +728,8 @@ static int cdce925_probe(struct i2c_client *client,
init.flags = CLK_SET_RATE_PARENT;
init.num_parents = 1;
for (i = 1; i < data->chip_info->num_outputs; ++i) {
init.name = kasprintf(GFP_KERNEL, "%s.Y%d",
client->dev.of_node->name, i+1);
init.name = kasprintf(GFP_KERNEL, "%pOFn.Y%d",
client->dev.of_node, i+1);
data->clk[i].chip = data;
data->clk[i].hw.init = &init;
data->clk[i].index = i;

View File

@@ -70,6 +70,30 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
}
EXPORT_SYMBOL_GPL(devm_clk_bulk_get);
int __must_check devm_clk_bulk_get_all(struct device *dev,
struct clk_bulk_data **clks)
{
struct clk_bulk_devres *devres;
int ret;
devres = devres_alloc(devm_clk_bulk_release,
sizeof(*devres), GFP_KERNEL);
if (!devres)
return -ENOMEM;
ret = clk_bulk_get_all(dev, &devres->clks);
if (ret > 0) {
*clks = devres->clks;
devres->num_clks = ret;
devres_add(dev, devres);
} else {
devres_free(devres);
}
return ret;
}
EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all);
static int devm_clk_match(struct device *dev, void *res, void *data)
{
struct clk **c = res;

View File

@@ -158,14 +158,14 @@ static struct clk *_of_fixed_factor_clk_setup(struct device_node *node)
int ret;
if (of_property_read_u32(node, "clock-div", &div)) {
pr_err("%s Fixed factor clock <%s> must have a clock-div property\n",
__func__, node->name);
pr_err("%s Fixed factor clock <%pOFn> must have a clock-div property\n",
__func__, node);
return ERR_PTR(-EIO);
}
if (of_property_read_u32(node, "clock-mult", &mult)) {
pr_err("%s Fixed factor clock <%s> must have a clock-mult property\n",
__func__, node->name);
pr_err("%s Fixed factor clock <%pOFn> must have a clock-mult property\n",
__func__, node);
return ERR_PTR(-EIO);
}

View File

@@ -200,6 +200,7 @@ static int of_fixed_clk_remove(struct platform_device *pdev)
{
struct clk *clk = platform_get_drvdata(pdev);
of_clk_del_provider(pdev->dev.of_node);
clk_unregister_fixed_rate(clk);
return 0;

View File

@@ -233,11 +233,11 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
if (IS_ERR(gpiod)) {
ret = PTR_ERR(gpiod);
if (ret == -EPROBE_DEFER)
pr_debug("%s: %s: GPIOs not yet available, retry later\n",
node->name, __func__);
pr_debug("%pOFn: %s: GPIOs not yet available, retry later\n",
node, __func__);
else
pr_err("%s: %s: Can't get '%s' named GPIO property\n",
node->name, __func__,
pr_err("%pOFn: %s: Can't get '%s' named GPIO property\n",
node, __func__,
gpio_name);
return ret;
}

View File

@@ -390,13 +390,13 @@ static void __init of_hsdk_pll_clk_setup(struct device_node *node)
ret = clk_hw_register(NULL, &pll_clk->hw);
if (ret) {
pr_err("failed to register %s clock\n", node->name);
pr_err("failed to register %pOFn clock\n", node);
goto err_unmap_spec_regs;
}
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clk->hw);
if (ret) {
pr_err("failed to add hw provider for %s clock\n", node->name);
pr_err("failed to add hw provider for %pOFn clock\n", node);
goto err_unmap_spec_regs;
}

View File

@@ -1,24 +1,9 @@
/*
* clk-max77686.c - Clock driver for Maxim 77686/MAX77802
*
* Copyright (C) 2012 Samsung Electornics
* Jonghwa Lee <jonghwa3.lee@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
// SPDX-License-Identifier: GPL-2.0+
//
// clk-max77686.c - Clock driver for Maxim 77686/MAX77802
//
// Copyright (C) 2012 Samsung Electornics
// Jonghwa Lee <jonghwa3.lee@samsung.com>
#include <linux/kernel.h>
#include <linux/slab.h>

View File

@@ -97,8 +97,8 @@ static void __init nomadik_src_init(void)
}
src_base = of_iomap(np, 0);
if (!src_base) {
pr_err("%s: must have src parent node with REGS (%s)\n",
__func__, np->name);
pr_err("%s: must have src parent node with REGS (%pOFn)\n",
__func__, np);
return;
}

View File

@@ -549,7 +549,7 @@ static void __init npcm7xx_clk_init(struct device_node *clk_np)
ret = of_address_to_resource(clk_np, 0, &res);
if (ret) {
pr_err("%s: failed to get resource, ret %d\n", clk_np->name,
pr_err("%pOFn: failed to get resource, ret %d\n", clk_np,
ret);
return;
}

View File

@@ -195,8 +195,8 @@ static void palmas_clks_get_clk_data(struct platform_device *pdev,
prop = PALMAS_EXT_CONTROL_NSLEEP;
break;
default:
dev_warn(&pdev->dev, "%s: Invalid ext control option: %u\n",
node->name, prop);
dev_warn(&pdev->dev, "%pOFn: Invalid ext control option: %u\n",
node, prop);
prop = 0;
break;
}

View File

@@ -945,8 +945,8 @@ static void __init core_mux_init(struct device_node *np)
rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
if (rc) {
pr_err("%s: Couldn't register clk provider for node %s: %d\n",
__func__, np->name, rc);
pr_err("%s: Couldn't register clk provider for node %pOFn: %d\n",
__func__, np, rc);
return;
}
}
@@ -1199,8 +1199,8 @@ static void __init legacy_pll_init(struct device_node *np, int idx)
rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
if (rc) {
pr_err("%s: Couldn't register clk provider for node %s: %d\n",
__func__, np->name, rc);
pr_err("%s: Couldn't register clk provider for node %pOFn: %d\n",
__func__, np, rc);
goto err_cell;
}
@@ -1360,7 +1360,7 @@ static void __init clockgen_init(struct device_node *np)
is_old_ls1021a = true;
}
if (!clockgen.regs) {
pr_err("%s(): %s: of_iomap() failed\n", __func__, np->name);
pr_err("%s(): %pOFn: of_iomap() failed\n", __func__, np);
return;
}
@@ -1406,8 +1406,8 @@ static void __init clockgen_init(struct device_node *np)
ret = of_clk_add_provider(np, clockgen_clk_get, &clockgen);
if (ret) {
pr_err("%s: Couldn't register clk provider for node %s: %d\n",
__func__, np->name, ret);
pr_err("%s: Couldn't register clk provider for node %pOFn: %d\n",
__func__, np, ret);
}
return;

View File

@@ -1,19 +1,8 @@
/*
* clk-s2mps11.c - Clock driver for S2MPS11.
*
* Copyright (C) 2013,2014 Samsung Electornics
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
// SPDX-License-Identifier: GPL-2.0+
//
// clk-s2mps11.c - Clock driver for S2MPS11.
//
// Copyright (C) 2013,2014 Samsung Electornics
#include <linux/module.h>
#include <linux/err.h>
@@ -28,12 +17,7 @@
#include <linux/mfd/samsung/s5m8767.h>
#include <linux/mfd/samsung/core.h>
enum {
S2MPS11_CLK_AP = 0,
S2MPS11_CLK_CP,
S2MPS11_CLK_BT,
S2MPS11_CLKS_NUM,
};
#include <dt-bindings/clock/samsung,s2mps11.h>
struct s2mps11_clk {
struct sec_pmic_dev *iodev;
@@ -245,6 +229,36 @@ static const struct platform_device_id s2mps11_clk_id[] = {
};
MODULE_DEVICE_TABLE(platform, s2mps11_clk_id);
#ifdef CONFIG_OF
/*
* Device is instantiated through parent MFD device and device matching is done
* through platform_device_id.
*
* However if device's DT node contains proper clock compatible and driver is
* built as a module, then the *module* matching will be done trough DT aliases.
* This requires of_device_id table. In the same time this will not change the
* actual *device* matching so do not add .of_match_table.
*/
static const struct of_device_id s2mps11_dt_match[] __used = {
{
.compatible = "samsung,s2mps11-clk",
.data = (void *)S2MPS11X,
}, {
.compatible = "samsung,s2mps13-clk",
.data = (void *)S2MPS13X,
}, {
.compatible = "samsung,s2mps14-clk",
.data = (void *)S2MPS14X,
}, {
.compatible = "samsung,s5m8767-clk",
.data = (void *)S5M8767X,
}, {
/* Sentinel */
},
};
MODULE_DEVICE_TABLE(of, s2mps11_dt_match);
#endif
static struct platform_driver s2mps11_clk_driver = {
.driver = {
.name = "s2mps11-clk",

View File

@@ -132,7 +132,7 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
count = handle->clk_ops->count_get(handle);
if (count < 0) {
dev_err(dev, "%s: invalid clock output count\n", np->name);
dev_err(dev, "%pOFn: invalid clock output count\n", np);
return -EINVAL;
}

View File

@@ -207,7 +207,7 @@ static int scpi_clk_add(struct device *dev, struct device_node *np,
count = of_property_count_strings(np, "clock-output-names");
if (count < 0) {
dev_err(dev, "%s: invalid clock output count\n", np->name);
dev_err(dev, "%pOFn: invalid clock output count\n", np);
return -EINVAL;
}
@@ -232,13 +232,13 @@ static int scpi_clk_add(struct device *dev, struct device_node *np,
if (of_property_read_string_index(np, "clock-output-names",
idx, &name)) {
dev_err(dev, "invalid clock name @ %s\n", np->name);
dev_err(dev, "invalid clock name @ %pOFn\n", np);
return -EINVAL;
}
if (of_property_read_u32_index(np, "clock-indices",
idx, &val)) {
dev_err(dev, "invalid clock index @ %s\n", np->name);
dev_err(dev, "invalid clock index @ %pOFn\n", np);
return -EINVAL;
}

View File

@@ -1215,8 +1215,8 @@ static int si5351_dt_parse(struct i2c_client *client,
/* per clkout properties */
for_each_child_of_node(np, child) {
if (of_property_read_u32(child, "reg", &num)) {
dev_err(&client->dev, "missing reg property of %s\n",
child->name);
dev_err(&client->dev, "missing reg property of %pOFn\n",
child);
goto put_child;
}

View File

@@ -1433,7 +1433,7 @@ static void __init stm32f4_rcc_init(struct device_node *np)
base = of_iomap(np, 0);
if (!base) {
pr_err("%s: unable to map resource\n", np->name);
pr_err("%pOFn: unable to map resource\n", np);
return;
}

View File

@@ -1216,7 +1216,7 @@ static void __init stm32h7_rcc_init(struct device_node *np)
/* get RCC base @ from DT */
base = of_iomap(np, 0);
if (!base) {
pr_err("%s: unable to map resource", np->name);
pr_err("%pOFn: unable to map resource", np);
goto err_free_clks;
}

View File

@@ -2088,7 +2088,7 @@ static void stm32mp1_rcc_init(struct device_node *np)
base = of_iomap(np, 0);
if (!base) {
pr_err("%s: unable to map resource", np->name);
pr_err("%pOFn: unable to map resource", np);
of_node_put(np);
return;
}

View File

@@ -54,13 +54,13 @@ static void __init tango4_clkgen_setup(struct device_node *np)
const char *parent = of_clk_get_parent_name(np, 0);
if (!base)
panic("%s: invalid address\n", np->name);
panic("%pOFn: invalid address\n", np);
if (readl(base + CPUCLK_DIV) & DIV_BYPASS)
panic("%s: unsupported cpuclk setup\n", np->name);
panic("%pOFn: unsupported cpuclk setup\n", np);
if (readl(base + SYSCLK_DIV) & DIV_BYPASS)
panic("%s: unsupported sysclk setup\n", np->name);
panic("%pOFn: unsupported sysclk setup\n", np);
writel(0x100, base + CPUCLK_DIV); /* disable frequency ramping */
@@ -77,9 +77,9 @@ static void __init tango4_clkgen_setup(struct device_node *np)
pp[3] = clk_register_fixed_factor(NULL, "sdio_clk", "cd6", 0, 1, 2);
if (IS_ERR(pp[0]) || IS_ERR(pp[1]) || IS_ERR(pp[2]) || IS_ERR(pp[3]))
panic("%s: clk registration failed\n", np->name);
panic("%pOFn: clk registration failed\n", np);
if (of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data))
panic("%s: clk provider registration failed\n", np->name);
panic("%pOFn: clk provider registration failed\n", np);
}
CLK_OF_DECLARE(tango4_clkgen, "sigma,tango4-clkgen", tango4_clkgen_setup);

View File

@@ -923,6 +923,101 @@ static int clk_core_enable_lock(struct clk_core *core)
return ret;
}
/**
* clk_gate_restore_context - restore context for poweroff
* @hw: the clk_hw pointer of clock whose state is to be restored
*
* The clock gate restore context function enables or disables
* the gate clocks based on the enable_count. This is done in cases
* where the clock context is lost and based on the enable_count
* the clock either needs to be enabled/disabled. This
* helps restore the state of gate clocks.
*/
void clk_gate_restore_context(struct clk_hw *hw)
{
struct clk_core *core = hw->core;
if (core->enable_count)
core->ops->enable(hw);
else
core->ops->disable(hw);
}
EXPORT_SYMBOL_GPL(clk_gate_restore_context);
static int clk_core_save_context(struct clk_core *core)
{
struct clk_core *child;
int ret = 0;
hlist_for_each_entry(child, &core->children, child_node) {
ret = clk_core_save_context(child);
if (ret < 0)
return ret;
}
if (core->ops && core->ops->save_context)
ret = core->ops->save_context(core->hw);
return ret;
}
static void clk_core_restore_context(struct clk_core *core)
{
struct clk_core *child;
if (core->ops && core->ops->restore_context)
core->ops->restore_context(core->hw);
hlist_for_each_entry(child, &core->children, child_node)
clk_core_restore_context(child);
}
/**
* clk_save_context - save clock context for poweroff
*
* Saves the context of the clock register for powerstates in which the
* contents of the registers will be lost. Occurs deep within the suspend
* code. Returns 0 on success.
*/
int clk_save_context(void)
{
struct clk_core *clk;
int ret;
hlist_for_each_entry(clk, &clk_root_list, child_node) {
ret = clk_core_save_context(clk);
if (ret < 0)
return ret;
}
hlist_for_each_entry(clk, &clk_orphan_list, child_node) {
ret = clk_core_save_context(clk);
if (ret < 0)
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(clk_save_context);
/**
* clk_restore_context - restore clock context after poweroff
*
* Restore the saved clock context upon resume.
*
*/
void clk_restore_context(void)
{
struct clk_core *core;
hlist_for_each_entry(core, &clk_root_list, child_node)
clk_core_restore_context(core);
hlist_for_each_entry(core, &clk_orphan_list, child_node)
clk_core_restore_context(core);
}
EXPORT_SYMBOL_GPL(clk_restore_context);
/**
* clk_enable - ungate a clock
* @clk: the clk being ungated

View File

@@ -303,24 +303,6 @@ static int davinci_lpsc_clk_reset(struct clk *clk, bool reset)
return 0;
}
/*
* REVISIT: These exported functions can be removed after a non-DT lookup is
* added to the reset controller framework and the davinci-rproc driver is
* updated to use the generic reset controller framework.
*/
int davinci_clk_reset_assert(struct clk *clk)
{
return davinci_lpsc_clk_reset(clk, true);
}
EXPORT_SYMBOL(davinci_clk_reset_assert);
int davinci_clk_reset_deassert(struct clk *clk)
{
return davinci_lpsc_clk_reset(clk, false);
}
EXPORT_SYMBOL(davinci_clk_reset_deassert);
static int davinci_psc_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{

View File

@@ -21,6 +21,13 @@ config COMMON_CLK_HI3660
help
Build the clock driver for hi3660.
config COMMON_CLK_HI3670
bool "Hi3670 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
default ARCH_HISI
help
Build the clock driver for hi3670.
config COMMON_CLK_HI3798CV200
tristate "Hi3798CV200 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST

View File

@@ -11,6 +11,7 @@ obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
obj-$(CONFIG_COMMON_CLK_HI3516CV300) += crg-hi3516cv300.o
obj-$(CONFIG_COMMON_CLK_HI3519) += clk-hi3519.o
obj-$(CONFIG_COMMON_CLK_HI3660) += clk-hi3660.o
obj-$(CONFIG_COMMON_CLK_HI3670) += clk-hi3670.o
obj-$(CONFIG_COMMON_CLK_HI3798CV200) += crg-hi3798cv200.o
obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o
obj-$(CONFIG_RESET_HISI) += reset.o

File diff suppressed because it is too large Load Diff

View File

@@ -109,9 +109,8 @@ struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev)
return NULL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rstc->membase = devm_ioremap(&pdev->dev,
res->start, resource_size(res));
if (!rstc->membase)
rstc->membase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(rstc->membase))
return NULL;
spin_lock_init(&rstc->lock);

View File

@@ -94,7 +94,7 @@ struct clk *imx_clk_cpu(const char *name, const char *parent_name,
init.name = name;
init.ops = &clk_cpu_ops;
init.flags = 0;
init.flags = CLK_IS_CRITICAL;
init.parent_names = &parent_name;
init.num_parents = 1;

View File

@@ -789,6 +789,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "axi", base + 0x74, 18);
clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_gate2_flags("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20, CLK_IS_CRITICAL);
clk[IMX6QDL_CLK_MMDC_CH1_AXI] = imx_clk_gate2("mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22);
clk[IMX6QDL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
clk[IMX6QDL_CLK_OCRAM] = imx_clk_gate2("ocram", "ahb", base + 0x74, 28);
clk[IMX6QDL_CLK_OPENVG_AXI] = imx_clk_gate2("openvg_axi", "axi", base + 0x74, 30);
clk[IMX6QDL_CLK_PCIE_AXI] = imx_clk_gate2("pcie_axi", "pcie_axi_sel", base + 0x78, 0);

View File

@@ -386,6 +386,8 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clks[IMX6SL_CLK_LCDIF_AXI] = imx_clk_gate2("lcdif_axi", "lcdif_axi_podf", base + 0x74, 6);
clks[IMX6SL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_pix_podf", base + 0x74, 8);
clks[IMX6SL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_pix_podf", base + 0x74, 10);
clks[IMX6SL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
clks[IMX6SL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
clks[IMX6SL_CLK_OCRAM] = imx_clk_gate2("ocram", "ocram_podf", base + 0x74, 28);
clks[IMX6SL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
clks[IMX6SL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);

View File

@@ -293,6 +293,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
clks[IMX6SLL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16);
clks[IMX6SLL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
clks[IMX6SLL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
clks[IMX6SLL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
clks[IMX6SLL_CLK_OCRAM] = imx_clk_gate_flags("ocram","ahb", base + 0x74, 28, CLK_IS_CRITICAL);
/* CCGR4 */

View File

@@ -431,6 +431,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clks[IMX6SX_CLK_MLB] = imx_clk_gate2("mlb", "ahb", base + 0x74, 18);
clks[IMX6SX_CLK_MMDC_P0_FAST] = imx_clk_gate2_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
clks[IMX6SX_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
clks[IMX6SX_CLK_OCRAM] = imx_clk_gate2_flags("ocram", "ocram_podf", base + 0x74, 28, CLK_IS_CRITICAL);
/* CCGR4 */

View File

@@ -408,6 +408,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16);
clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL);
clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL);
clks[IMX6UL_CLK_MMDC_P1_IPG] = imx_clk_gate2("mmdc_p1_ipg", "ipg", base + 0x74, 26);
clks[IMX6UL_CLK_AXI] = imx_clk_gate_flags("axi", "axi_podf", base + 0x74, 28, CLK_IS_CRITICAL);
/* CCGR4 */

View File

@@ -379,14 +379,6 @@ static const char *pll_enet_bypass_sel[] = { "pll_enet_main", "pll_enet_main_src
static const char *pll_audio_bypass_sel[] = { "pll_audio_main", "pll_audio_main_src", };
static const char *pll_video_bypass_sel[] = { "pll_video_main", "pll_video_main_src", };
static int const clks_init_on[] __initconst = {
IMX7D_ARM_A7_ROOT_CLK, IMX7D_MAIN_AXI_ROOT_CLK,
IMX7D_PLL_SYS_MAIN_480M_CLK, IMX7D_NAND_USDHC_BUS_ROOT_CLK,
IMX7D_DRAM_PHYM_ROOT_CLK, IMX7D_DRAM_ROOT_CLK,
IMX7D_DRAM_PHYM_ALT_ROOT_CLK, IMX7D_DRAM_ALT_ROOT_CLK,
IMX7D_AHB_CHANNEL_ROOT_CLK, IMX7D_IPG_ROOT_CLK,
};
static struct clk_onecell_data clk_data;
static struct clk ** const uart_clks[] __initconst = {
@@ -404,7 +396,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
int i;
clks[IMX7D_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
clks[IMX7D_OSC_24M_CLK] = of_clk_get_by_name(ccm_node, "osc");
@@ -467,7 +458,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_PLL_SYS_MAIN_120M] = imx_clk_fixed_factor("pll_sys_main_120m", "pll_sys_main_clk", 1, 4);
clks[IMX7D_PLL_DRAM_MAIN_533M] = imx_clk_fixed_factor("pll_dram_533m", "pll_dram_main_clk", 1, 2);
clks[IMX7D_PLL_SYS_MAIN_480M_CLK] = imx_clk_gate_dis("pll_sys_main_480m_clk", "pll_sys_main_480m", base + 0xb0, 4);
clks[IMX7D_PLL_SYS_MAIN_480M_CLK] = imx_clk_gate_dis_flags("pll_sys_main_480m_clk", "pll_sys_main_480m", base + 0xb0, 4, CLK_IS_CRITICAL);
clks[IMX7D_PLL_SYS_MAIN_240M_CLK] = imx_clk_gate_dis("pll_sys_main_240m_clk", "pll_sys_main_240m", base + 0xb0, 5);
clks[IMX7D_PLL_SYS_MAIN_120M_CLK] = imx_clk_gate_dis("pll_sys_main_120m_clk", "pll_sys_main_120m", base + 0xb0, 6);
clks[IMX7D_PLL_DRAM_MAIN_533M_CLK] = imx_clk_gate("pll_dram_533m_clk", "pll_dram_533m", base + 0x70, 12);
@@ -720,7 +711,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_divider2("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6);
clks[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_divider2("nand_usdhc_root_clk", "nand_usdhc_pre_div", base + 0x8980, 0, 6);
clks[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_divider2("ahb_root_clk", "ahb_pre_div", base + 0x9000, 0, 6);
clks[IMX7D_IPG_ROOT_CLK] = imx_clk_divider2("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2);
clks[IMX7D_IPG_ROOT_CLK] = imx_clk_divider_flags("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE | CLK_SET_RATE_PARENT);
clks[IMX7D_DRAM_ROOT_DIV] = imx_clk_divider2("dram_post_div", "dram_cg", base + 0x9880, 0, 3);
clks[IMX7D_DRAM_PHYM_ALT_ROOT_DIV] = imx_clk_divider2("dram_phym_alt_post_div", "dram_phym_alt_pre_div", base + 0xa000, 0, 3);
clks[IMX7D_DRAM_ALT_ROOT_DIV] = imx_clk_divider2("dram_alt_post_div", "dram_alt_pre_div", base + 0xa080, 0, 3);
@@ -784,17 +775,17 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_CLKO1_ROOT_DIV] = imx_clk_divider2("clko1_post_div", "clko1_pre_div", base + 0xbd80, 0, 6);
clks[IMX7D_CLKO2_ROOT_DIV] = imx_clk_divider2("clko2_post_div", "clko2_pre_div", base + 0xbe00, 0, 6);
clks[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_gate4("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0);
clks[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_gate2_flags("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0, CLK_OPS_PARENT_ENABLE);
clks[IMX7D_ARM_M4_ROOT_CLK] = imx_clk_gate4("arm_m4_root_clk", "arm_m4_div", base + 0x4010, 0);
clks[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_gate4("main_axi_root_clk", "axi_post_div", base + 0x4040, 0);
clks[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_gate2_flags("main_axi_root_clk", "axi_post_div", base + 0x4040, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
clks[IMX7D_DISP_AXI_ROOT_CLK] = imx_clk_gate4("disp_axi_root_clk", "disp_axi_post_div", base + 0x4050, 0);
clks[IMX7D_ENET_AXI_ROOT_CLK] = imx_clk_gate4("enet_axi_root_clk", "enet_axi_post_div", base + 0x4060, 0);
clks[IMX7D_OCRAM_CLK] = imx_clk_gate4("ocram_clk", "main_axi_root_clk", base + 0x4110, 0);
clks[IMX7D_OCRAM_S_CLK] = imx_clk_gate4("ocram_s_clk", "ahb_root_clk", base + 0x4120, 0);
clks[IMX7D_DRAM_ROOT_CLK] = imx_clk_gate4("dram_root_clk", "dram_post_div", base + 0x4130, 0);
clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate4("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0);
clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate4("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0);
clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0);
clks[IMX7D_DRAM_ROOT_CLK] = imx_clk_gate2_flags("dram_root_clk", "dram_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate2_flags("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate2_flags("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate2_flags("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE);
clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0);
clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
@@ -883,9 +874,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clk_data.clk_num = ARRAY_SIZE(clks);
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clks[clks_init_on[i]]);
clk_set_parent(clks[IMX7D_PLL_ARM_MAIN_BYPASS], clks[IMX7D_PLL_ARM_MAIN]);
clk_set_parent(clks[IMX7D_PLL_DRAM_MAIN_BYPASS], clks[IMX7D_PLL_DRAM_MAIN]);
clk_set_parent(clks[IMX7D_PLL_SYS_MAIN_BYPASS], clks[IMX7D_PLL_SYS_MAIN]);

View File

@@ -137,6 +137,13 @@ static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent,
shift, CLK_GATE_SET_TO_DISABLE, &imx_ccm_lock);
}
static inline struct clk *imx_clk_gate_dis_flags(const char *name, const char *parent,
void __iomem *reg, u8 shift, unsigned long flags)
{
return clk_register_gate(NULL, name, parent, flags | CLK_SET_RATE_PARENT, reg,
shift, CLK_GATE_SET_TO_DISABLE, &imx_ccm_lock);
}
static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{

View File

@@ -0,0 +1,47 @@
menu "Ingenic JZ47xx CGU drivers"
depends on MIPS
config INGENIC_CGU_COMMON
bool
config INGENIC_CGU_JZ4740
bool "Ingenic JZ4740 CGU driver"
default MACH_JZ4740
select INGENIC_CGU_COMMON
help
Support the clocks provided by the CGU hardware on Ingenic JZ4740
and compatible SoCs.
If building for a JZ4740 SoC, you want to say Y here.
config INGENIC_CGU_JZ4725B
bool "Ingenic JZ4725B CGU driver"
default MACH_JZ4725B
select INGENIC_CGU_COMMON
help
Support the clocks provided by the CGU hardware on Ingenic JZ4725B
and compatible SoCs.
If building for a JZ4725B SoC, you want to say Y here.
config INGENIC_CGU_JZ4770
bool "Ingenic JZ4770 CGU driver"
default MACH_JZ4770
select INGENIC_CGU_COMMON
help
Support the clocks provided by the CGU hardware on Ingenic JZ4770
and compatible SoCs.
If building for a JZ4770 SoC, you want to say Y here.
config INGENIC_CGU_JZ4780
bool "Ingenic JZ4780 CGU driver"
default MACH_JZ4780
select INGENIC_CGU_COMMON
help
Support the clocks provided by the CGU hardware on Ingenic JZ4780
and compatible SoCs.
If building for a JZ4780 SoC, you want to say Y here.
endmenu

View File

@@ -1,4 +1,5 @@
obj-y += cgu.o
obj-$(CONFIG_MACH_JZ4740) += jz4740-cgu.o
obj-$(CONFIG_MACH_JZ4770) += jz4770-cgu.o
obj-$(CONFIG_MACH_JZ4780) += jz4780-cgu.o
obj-$(CONFIG_INGENIC_CGU_COMMON) += cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4740) += jz4740-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4725B) += jz4725b-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4770) += jz4770-cgu.o
obj-$(CONFIG_INGENIC_CGU_JZ4780) += jz4780-cgu.o

View File

@@ -0,0 +1,225 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Ingenic JZ4725B SoC CGU driver
*
* Copyright (C) 2018 Paul Cercueil
* Author: Paul Cercueil <paul@crapouillou.net>
*/
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <dt-bindings/clock/jz4725b-cgu.h>
#include "cgu.h"
/* CGU register offsets */
#define CGU_REG_CPCCR 0x00
#define CGU_REG_LCR 0x04
#define CGU_REG_CPPCR 0x10
#define CGU_REG_CLKGR 0x20
#define CGU_REG_OPCR 0x24
#define CGU_REG_I2SCDR 0x60
#define CGU_REG_LPCDR 0x64
#define CGU_REG_MSCCDR 0x68
#define CGU_REG_SSICDR 0x74
#define CGU_REG_CIMCDR 0x78
/* bits within the LCR register */
#define LCR_SLEEP BIT(0)
static struct ingenic_cgu *cgu;
static const s8 pll_od_encoding[4] = {
0x0, 0x1, -1, 0x3,
};
static const struct ingenic_cgu_clk_info jz4725b_cgu_clocks[] = {
/* External clocks */
[JZ4725B_CLK_EXT] = { "ext", CGU_CLK_EXT },
[JZ4725B_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
[JZ4725B_CLK_PLL] = {
"pll", CGU_CLK_PLL,
.parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
.pll = {
.reg = CGU_REG_CPPCR,
.m_shift = 23,
.m_bits = 9,
.m_offset = 2,
.n_shift = 18,
.n_bits = 5,
.n_offset = 2,
.od_shift = 16,
.od_bits = 2,
.od_max = 4,
.od_encoding = pll_od_encoding,
.stable_bit = 10,
.bypass_bit = 9,
.enable_bit = 8,
},
},
/* Muxes & dividers */
[JZ4725B_CLK_PLL_HALF] = {
"pll half", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
.div = { CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1 },
},
[JZ4725B_CLK_CCLK] = {
"cclk", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
.div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
},
[JZ4725B_CLK_HCLK] = {
"hclk", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
.div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
},
[JZ4725B_CLK_PCLK] = {
"pclk", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
.div = { CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1 },
},
[JZ4725B_CLK_MCLK] = {
"mclk", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
.div = { CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1 },
},
[JZ4725B_CLK_IPU] = {
"ipu", CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4725B_CLK_PLL, -1, -1, -1 },
.div = { CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1 },
.gate = { CGU_REG_CLKGR, 13 },
},
[JZ4725B_CLK_LCD] = {
"lcd", CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 },
.div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
.gate = { CGU_REG_CLKGR, 9 },
},
[JZ4725B_CLK_I2S] = {
"i2s", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 },
.mux = { CGU_REG_CPCCR, 31, 1 },
.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
.gate = { CGU_REG_CLKGR, 6 },
},
[JZ4725B_CLK_SPI] = {
"spi", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
.parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL, -1, -1 },
.mux = { CGU_REG_SSICDR, 31, 1 },
.div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 },
.gate = { CGU_REG_CLKGR, 4 },
},
[JZ4725B_CLK_MMC_MUX] = {
"mmc_mux", CGU_CLK_DIV,
.parents = { JZ4725B_CLK_PLL_HALF, -1, -1, -1 },
.div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 },
},
[JZ4725B_CLK_UDC] = {
"udc", CGU_CLK_MUX | CGU_CLK_DIV,
.parents = { JZ4725B_CLK_EXT, JZ4725B_CLK_PLL_HALF, -1, -1 },
.mux = { CGU_REG_CPCCR, 29, 1 },
.div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 },
},
/* Gate-only clocks */
[JZ4725B_CLK_UART] = {
"uart", CGU_CLK_GATE,
.parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
.gate = { CGU_REG_CLKGR, 0 },
},
[JZ4725B_CLK_DMA] = {
"dma", CGU_CLK_GATE,
.parents = { JZ4725B_CLK_PCLK, -1, -1, -1 },
.gate = { CGU_REG_CLKGR, 12 },
},
[JZ4725B_CLK_ADC] = {
"adc", CGU_CLK_GATE,
.parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
.gate = { CGU_REG_CLKGR, 7 },
},
[JZ4725B_CLK_I2C] = {
"i2c", CGU_CLK_GATE,
.parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
.gate = { CGU_REG_CLKGR, 3 },
},
[JZ4725B_CLK_AIC] = {
"aic", CGU_CLK_GATE,
.parents = { JZ4725B_CLK_EXT, -1, -1, -1 },
.gate = { CGU_REG_CLKGR, 5 },
},
[JZ4725B_CLK_MMC0] = {
"mmc0", CGU_CLK_GATE,
.parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 },
.gate = { CGU_REG_CLKGR, 6 },
},
[JZ4725B_CLK_MMC1] = {
"mmc1", CGU_CLK_GATE,
.parents = { JZ4725B_CLK_MMC_MUX, -1, -1, -1 },
.gate = { CGU_REG_CLKGR, 16 },
},
[JZ4725B_CLK_BCH] = {
"bch", CGU_CLK_GATE,
.parents = { JZ4725B_CLK_MCLK/* not sure */, -1, -1, -1 },
.gate = { CGU_REG_CLKGR, 11 },
},
[JZ4725B_CLK_TCU] = {
"tcu", CGU_CLK_GATE,
.parents = { JZ4725B_CLK_EXT/* not sure */, -1, -1, -1 },
.gate = { CGU_REG_CLKGR, 1 },
},
[JZ4725B_CLK_EXT512] = {
"ext/512", CGU_CLK_FIXDIV,
.parents = { JZ4725B_CLK_EXT },
/* Doc calls it EXT512, but it seems to be /256... */
.fixdiv = { 256 },
},
[JZ4725B_CLK_RTC] = {
"rtc", CGU_CLK_MUX,
.parents = { JZ4725B_CLK_EXT512, JZ4725B_CLK_OSC32K, -1, -1 },
.mux = { CGU_REG_OPCR, 2, 1},
},
};
static void __init jz4725b_cgu_init(struct device_node *np)
{
int retval;
cgu = ingenic_cgu_new(jz4725b_cgu_clocks,
ARRAY_SIZE(jz4725b_cgu_clocks), np);
if (!cgu) {
pr_err("%s: failed to initialise CGU\n", __func__);
return;
}
retval = ingenic_cgu_register_clocks(cgu);
if (retval)
pr_err("%s: failed to register CGU Clocks\n", __func__);
}
CLK_OF_DECLARE(jz4725b_cgu, "ingenic,jz4725b-cgu", jz4725b_cgu_init);

View File

@@ -7,7 +7,7 @@ config COMMON_CLK_KEYSTONE
config TI_SCI_CLK
tristate "TI System Control Interface clock drivers"
depends on (ARCH_KEYSTONE || COMPILE_TEST) && OF
depends on (ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST) && OF
depends on TI_SCI_PROTOCOL
default ARCH_KEYSTONE
---help---

View File

@@ -245,7 +245,7 @@ static void __init of_psc_clk_init(struct device_node *node, spinlock_t *lock)
return;
}
pr_err("%s: error registering clk %s\n", __func__, node->name);
pr_err("%s: error registering clk %pOFn\n", __func__, node);
unmap_domain:
iounmap(data->domain_base);
@@ -266,3 +266,8 @@ static void __init of_keystone_psc_clk_init(struct device_node *node)
}
CLK_OF_DECLARE(keystone_gate_clk, "ti,keystone,psc-clock",
of_keystone_psc_clk_init);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Clock driver for Keystone 2 based devices");
MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
MODULE_AUTHOR("Santosh Shilimkar <santosh.shilimkar@ti.com>");

View File

@@ -219,7 +219,7 @@ static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl)
}
out:
pr_err("%s: error initializing pll %s\n", __func__, node->name);
pr_err("%s: error initializing pll %pOFn\n", __func__, node);
kfree(pll_data);
}
@@ -338,3 +338,8 @@ static void __init of_pll_mux_clk_init(struct device_node *node)
pr_err("%s: error registering mux %s\n", __func__, clk_name);
}
CLK_OF_DECLARE(pll_mux_clock, "ti,keystone,pll-mux-clock", of_pll_mux_clk_init);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("PLL clock driver for Keystone devices");
MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
MODULE_AUTHOR("Santosh Shilimkar <santosh.shilimkar@ti.com>");

View File

@@ -249,11 +249,6 @@ static const char * const msdc30_parents[] = {
"univpll2_d4"
};
static const char * const audio_parents[] = {
"clk26m",
"syspll1_d16"
};
static const char * const aud_intbus_parents[] = {
"clk26m",
"syspll1_d4",

View File

@@ -101,10 +101,16 @@ static const char * const mst_mux_parent_names[] = {
"axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7",
};
#define AXG_MST_MCLK_MUX(_name, _reg) \
AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \
#define AXG_MST_MUX(_name, _reg, _flag) \
AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag, \
mst_mux_parent_names, CLK_SET_RATE_PARENT)
#define AXG_MST_MCLK_MUX(_name, _reg) \
AXG_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST)
#define AXG_MST_SYS_MUX(_name, _reg) \
AXG_MST_MUX(_name, _reg, 0)
static AXG_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL);
static AXG_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL);
static AXG_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL);
@@ -112,13 +118,19 @@ static AXG_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL);
static AXG_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL);
static AXG_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL);
static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
static AXG_MST_MCLK_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
static AXG_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0);
static AXG_MST_MCLK_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1);
static AXG_MST_SYS_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
static AXG_MST_SYS_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1);
#define AXG_MST_MCLK_DIV(_name, _reg) \
AXG_AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \
"axg_"#_name"_sel", CLK_SET_RATE_PARENT) \
#define AXG_MST_DIV(_name, _reg, _flag) \
AXG_AUD_DIV(_name##_div, _reg, 0, 16, _flag, \
"axg_"#_name"_sel", CLK_SET_RATE_PARENT) \
#define AXG_MST_MCLK_DIV(_name, _reg) \
AXG_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST)
#define AXG_MST_SYS_DIV(_name, _reg) \
AXG_MST_DIV(_name, _reg, 0)
static AXG_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL);
static AXG_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL);
@@ -127,12 +139,12 @@ static AXG_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL);
static AXG_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL);
static AXG_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL);
static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL);
static AXG_MST_MCLK_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
static AXG_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0);
static AXG_MST_MCLK_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1);
static AXG_MST_SYS_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
static AXG_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1);
#define AXG_MST_MCLK_GATE(_name, _reg) \
AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \
#define AXG_MST_MCLK_GATE(_name, _reg) \
AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \
CLK_SET_RATE_PARENT)
static AXG_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL);

View File

@@ -22,8 +22,13 @@
static DEFINE_SPINLOCK(meson_clk_lock);
static struct clk_regmap axg_fixed_pll = {
static struct clk_regmap axg_fixed_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = HHI_MPLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_MPLL_CNTL,
.shift = 0,
@@ -34,11 +39,6 @@ static struct clk_regmap axg_fixed_pll = {
.shift = 9,
.width = 5,
},
.od = {
.reg_off = HHI_MPLL_CNTL,
.shift = 16,
.width = 2,
},
.frac = {
.reg_off = HHI_MPLL_CNTL2,
.shift = 0,
@@ -56,15 +56,39 @@ static struct clk_regmap axg_fixed_pll = {
},
},
.hw.init = &(struct clk_init_data){
.name = "fixed_pll",
.name = "fixed_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
},
};
static struct clk_regmap axg_sys_pll = {
static struct clk_regmap axg_fixed_pll = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_MPLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "fixed_pll",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "fixed_pll_dco" },
.num_parents = 1,
/*
* This clock won't ever change at runtime so
* CLK_SET_RATE_PARENT is not required
*/
},
};
static struct clk_regmap axg_sys_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 0,
@@ -75,11 +99,6 @@ static struct clk_regmap axg_sys_pll = {
.shift = 9,
.width = 5,
},
.od = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 16,
.width = 2,
},
.l = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 31,
@@ -92,102 +111,59 @@ static struct clk_regmap axg_sys_pll = {
},
},
.hw.init = &(struct clk_init_data){
.name = "sys_pll",
.name = "sys_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static const struct pll_rate_table axg_gp0_pll_rate_table[] = {
PLL_RATE(240000000, 40, 1, 2),
PLL_RATE(246000000, 41, 1, 2),
PLL_RATE(252000000, 42, 1, 2),
PLL_RATE(258000000, 43, 1, 2),
PLL_RATE(264000000, 44, 1, 2),
PLL_RATE(270000000, 45, 1, 2),
PLL_RATE(276000000, 46, 1, 2),
PLL_RATE(282000000, 47, 1, 2),
PLL_RATE(288000000, 48, 1, 2),
PLL_RATE(294000000, 49, 1, 2),
PLL_RATE(300000000, 50, 1, 2),
PLL_RATE(306000000, 51, 1, 2),
PLL_RATE(312000000, 52, 1, 2),
PLL_RATE(318000000, 53, 1, 2),
PLL_RATE(324000000, 54, 1, 2),
PLL_RATE(330000000, 55, 1, 2),
PLL_RATE(336000000, 56, 1, 2),
PLL_RATE(342000000, 57, 1, 2),
PLL_RATE(348000000, 58, 1, 2),
PLL_RATE(354000000, 59, 1, 2),
PLL_RATE(360000000, 60, 1, 2),
PLL_RATE(366000000, 61, 1, 2),
PLL_RATE(372000000, 62, 1, 2),
PLL_RATE(378000000, 63, 1, 2),
PLL_RATE(384000000, 64, 1, 2),
PLL_RATE(390000000, 65, 1, 3),
PLL_RATE(396000000, 66, 1, 3),
PLL_RATE(402000000, 67, 1, 3),
PLL_RATE(408000000, 68, 1, 3),
PLL_RATE(480000000, 40, 1, 1),
PLL_RATE(492000000, 41, 1, 1),
PLL_RATE(504000000, 42, 1, 1),
PLL_RATE(516000000, 43, 1, 1),
PLL_RATE(528000000, 44, 1, 1),
PLL_RATE(540000000, 45, 1, 1),
PLL_RATE(552000000, 46, 1, 1),
PLL_RATE(564000000, 47, 1, 1),
PLL_RATE(576000000, 48, 1, 1),
PLL_RATE(588000000, 49, 1, 1),
PLL_RATE(600000000, 50, 1, 1),
PLL_RATE(612000000, 51, 1, 1),
PLL_RATE(624000000, 52, 1, 1),
PLL_RATE(636000000, 53, 1, 1),
PLL_RATE(648000000, 54, 1, 1),
PLL_RATE(660000000, 55, 1, 1),
PLL_RATE(672000000, 56, 1, 1),
PLL_RATE(684000000, 57, 1, 1),
PLL_RATE(696000000, 58, 1, 1),
PLL_RATE(708000000, 59, 1, 1),
PLL_RATE(720000000, 60, 1, 1),
PLL_RATE(732000000, 61, 1, 1),
PLL_RATE(744000000, 62, 1, 1),
PLL_RATE(756000000, 63, 1, 1),
PLL_RATE(768000000, 64, 1, 1),
PLL_RATE(780000000, 65, 1, 1),
PLL_RATE(792000000, 66, 1, 1),
PLL_RATE(804000000, 67, 1, 1),
PLL_RATE(816000000, 68, 1, 1),
PLL_RATE(960000000, 40, 1, 0),
PLL_RATE(984000000, 41, 1, 0),
PLL_RATE(1008000000, 42, 1, 0),
PLL_RATE(1032000000, 43, 1, 0),
PLL_RATE(1056000000, 44, 1, 0),
PLL_RATE(1080000000, 45, 1, 0),
PLL_RATE(1104000000, 46, 1, 0),
PLL_RATE(1128000000, 47, 1, 0),
PLL_RATE(1152000000, 48, 1, 0),
PLL_RATE(1176000000, 49, 1, 0),
PLL_RATE(1200000000, 50, 1, 0),
PLL_RATE(1224000000, 51, 1, 0),
PLL_RATE(1248000000, 52, 1, 0),
PLL_RATE(1272000000, 53, 1, 0),
PLL_RATE(1296000000, 54, 1, 0),
PLL_RATE(1320000000, 55, 1, 0),
PLL_RATE(1344000000, 56, 1, 0),
PLL_RATE(1368000000, 57, 1, 0),
PLL_RATE(1392000000, 58, 1, 0),
PLL_RATE(1416000000, 59, 1, 0),
PLL_RATE(1440000000, 60, 1, 0),
PLL_RATE(1464000000, 61, 1, 0),
PLL_RATE(1488000000, 62, 1, 0),
PLL_RATE(1512000000, 63, 1, 0),
PLL_RATE(1536000000, 64, 1, 0),
PLL_RATE(1560000000, 65, 1, 0),
PLL_RATE(1584000000, 66, 1, 0),
PLL_RATE(1608000000, 67, 1, 0),
PLL_RATE(1632000000, 68, 1, 0),
static struct clk_regmap axg_sys_pll = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_SYS_PLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "sys_pll",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "sys_pll_dco" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static const struct pll_params_table axg_gp0_pll_params_table[] = {
PLL_PARAMS(40, 1),
PLL_PARAMS(41, 1),
PLL_PARAMS(42, 1),
PLL_PARAMS(43, 1),
PLL_PARAMS(44, 1),
PLL_PARAMS(45, 1),
PLL_PARAMS(46, 1),
PLL_PARAMS(47, 1),
PLL_PARAMS(48, 1),
PLL_PARAMS(49, 1),
PLL_PARAMS(50, 1),
PLL_PARAMS(51, 1),
PLL_PARAMS(52, 1),
PLL_PARAMS(53, 1),
PLL_PARAMS(54, 1),
PLL_PARAMS(55, 1),
PLL_PARAMS(56, 1),
PLL_PARAMS(57, 1),
PLL_PARAMS(58, 1),
PLL_PARAMS(59, 1),
PLL_PARAMS(60, 1),
PLL_PARAMS(61, 1),
PLL_PARAMS(62, 1),
PLL_PARAMS(63, 1),
PLL_PARAMS(64, 1),
PLL_PARAMS(65, 1),
PLL_PARAMS(66, 1),
PLL_PARAMS(67, 1),
PLL_PARAMS(68, 1),
{ /* sentinel */ },
};
@@ -197,11 +173,15 @@ static const struct reg_sequence axg_gp0_init_regs[] = {
{ .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 },
{ .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d },
{ .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 },
{ .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 },
};
static struct clk_regmap axg_gp0_pll = {
static struct clk_regmap axg_gp0_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 0,
@@ -212,11 +192,6 @@ static struct clk_regmap axg_gp0_pll = {
.shift = 9,
.width = 5,
},
.od = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 16,
.width = 2,
},
.frac = {
.reg_off = HHI_GP0_PLL_CNTL1,
.shift = 0,
@@ -232,29 +207,49 @@ static struct clk_regmap axg_gp0_pll = {
.shift = 29,
.width = 1,
},
.table = axg_gp0_pll_rate_table,
.table = axg_gp0_pll_params_table,
.init_regs = axg_gp0_init_regs,
.init_count = ARRAY_SIZE(axg_gp0_init_regs),
},
.hw.init = &(struct clk_init_data){
.name = "gp0_pll",
.name = "gp0_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
},
};
static struct clk_regmap axg_gp0_pll = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_GP0_PLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "gp0_pll",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "gp0_pll_dco" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static const struct reg_sequence axg_hifi_init_regs[] = {
{ .reg = HHI_HIFI_PLL_CNTL1, .def = 0xc084b000 },
{ .reg = HHI_HIFI_PLL_CNTL2, .def = 0xb75020be },
{ .reg = HHI_HIFI_PLL_CNTL3, .def = 0x0a6a3a88 },
{ .reg = HHI_HIFI_PLL_CNTL4, .def = 0xc000004d },
{ .reg = HHI_HIFI_PLL_CNTL5, .def = 0x00058000 },
{ .reg = HHI_HIFI_PLL_CNTL, .def = 0x40010250 },
};
static struct clk_regmap axg_hifi_pll = {
static struct clk_regmap axg_hifi_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = HHI_HIFI_PLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_HIFI_PLL_CNTL,
.shift = 0,
@@ -265,11 +260,6 @@ static struct clk_regmap axg_hifi_pll = {
.shift = 9,
.width = 5,
},
.od = {
.reg_off = HHI_HIFI_PLL_CNTL,
.shift = 16,
.width = 2,
},
.frac = {
.reg_off = HHI_HIFI_PLL_CNTL5,
.shift = 0,
@@ -285,19 +275,35 @@ static struct clk_regmap axg_hifi_pll = {
.shift = 29,
.width = 1,
},
.table = axg_gp0_pll_rate_table,
.table = axg_gp0_pll_params_table,
.init_regs = axg_hifi_init_regs,
.init_count = ARRAY_SIZE(axg_hifi_init_regs),
.flags = CLK_MESON_PLL_ROUND_CLOSEST,
},
.hw.init = &(struct clk_init_data){
.name = "hifi_pll",
.name = "hifi_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
},
};
static struct clk_regmap axg_hifi_pll = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_HIFI_PLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "hifi_pll",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "hifi_pll_dco" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_fixed_factor axg_fclk_div2_div = {
.mult = 1,
.div = 2,
@@ -625,29 +631,31 @@ static struct clk_regmap axg_mpll3 = {
},
};
static const struct pll_rate_table axg_pcie_pll_rate_table[] = {
static const struct pll_params_table axg_pcie_pll_params_table[] = {
{
.rate = 100000000,
.m = 200,
.n = 3,
.od = 1,
.od2 = 3,
.m = 200,
.n = 3,
},
{ /* sentinel */ },
};
static const struct reg_sequence axg_pcie_init_regs[] = {
{ .reg = HHI_PCIE_PLL_CNTL, .def = 0x400106c8 },
{ .reg = HHI_PCIE_PLL_CNTL1, .def = 0x0084a2aa },
{ .reg = HHI_PCIE_PLL_CNTL2, .def = 0xb75020be },
{ .reg = HHI_PCIE_PLL_CNTL3, .def = 0x0a47488e },
{ .reg = HHI_PCIE_PLL_CNTL4, .def = 0xc000004d },
{ .reg = HHI_PCIE_PLL_CNTL5, .def = 0x00078000 },
{ .reg = HHI_PCIE_PLL_CNTL6, .def = 0x002323c6 },
{ .reg = HHI_PCIE_PLL_CNTL, .def = 0x400106c8 },
};
static struct clk_regmap axg_pcie_pll = {
static struct clk_regmap axg_pcie_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = HHI_PCIE_PLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_PCIE_PLL_CNTL,
.shift = 0,
@@ -658,16 +666,6 @@ static struct clk_regmap axg_pcie_pll = {
.shift = 9,
.width = 5,
},
.od = {
.reg_off = HHI_PCIE_PLL_CNTL,
.shift = 16,
.width = 2,
},
.od2 = {
.reg_off = HHI_PCIE_PLL_CNTL6,
.shift = 6,
.width = 2,
},
.frac = {
.reg_off = HHI_PCIE_PLL_CNTL1,
.shift = 0,
@@ -683,29 +681,63 @@ static struct clk_regmap axg_pcie_pll = {
.shift = 29,
.width = 1,
},
.table = axg_pcie_pll_rate_table,
.table = axg_pcie_pll_params_table,
.init_regs = axg_pcie_init_regs,
.init_count = ARRAY_SIZE(axg_pcie_init_regs),
},
.hw.init = &(struct clk_init_data){
.name = "pcie_pll",
.name = "pcie_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
},
};
static struct clk_regmap axg_pcie_pll_od = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_PCIE_PLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "pcie_pll_od",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "pcie_pll_dco" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap axg_pcie_pll = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_PCIE_PLL_CNTL6,
.shift = 6,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "pcie_pll",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "pcie_pll_od" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap axg_pcie_mux = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_PCIE_PLL_CNTL6,
.mask = 0x1,
.shift = 2,
/* skip the parent mpll3, reserved for debug */
.table = (u32[]){ 1 },
},
.hw.init = &(struct clk_init_data){
.name = "pcie_mux",
.ops = &clk_regmap_mux_ops,
.parent_names = (const char *[]){ "mpll3", "pcie_pll" },
.num_parents = 2,
.parent_names = (const char *[]){ "pcie_pll" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
@@ -1107,6 +1139,12 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = {
[CLKID_GEN_CLK_SEL] = &axg_gen_clk_sel.hw,
[CLKID_GEN_CLK_DIV] = &axg_gen_clk_div.hw,
[CLKID_GEN_CLK] = &axg_gen_clk.hw,
[CLKID_SYS_PLL_DCO] = &axg_sys_pll_dco.hw,
[CLKID_FIXED_PLL_DCO] = &axg_fixed_pll_dco.hw,
[CLKID_GP0_PLL_DCO] = &axg_gp0_pll_dco.hw,
[CLKID_HIFI_PLL_DCO] = &axg_hifi_pll_dco.hw,
[CLKID_PCIE_PLL_DCO] = &axg_pcie_pll_dco.hw,
[CLKID_PCIE_PLL_OD] = &axg_pcie_pll_od.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
@@ -1185,6 +1223,8 @@ static struct clk_regmap *const axg_clk_regmaps[] = {
&axg_fclk_div4,
&axg_fclk_div5,
&axg_fclk_div7,
&axg_pcie_pll_dco,
&axg_pcie_pll_od,
&axg_pcie_pll,
&axg_pcie_mux,
&axg_pcie_ref,
@@ -1194,6 +1234,12 @@ static struct clk_regmap *const axg_clk_regmaps[] = {
&axg_gen_clk_sel,
&axg_gen_clk_div,
&axg_gen_clk,
&axg_fixed_pll_dco,
&axg_sys_pll_dco,
&axg_gp0_pll_dco,
&axg_hifi_pll_dco,
&axg_pcie_pll_dco,
&axg_pcie_pll_od,
};
static const struct of_device_id clkc_match_table[] = {

View File

@@ -133,8 +133,14 @@
#define CLKID_PCIE_REF 78
#define CLKID_GEN_CLK_SEL 82
#define CLKID_GEN_CLK_DIV 83
#define CLKID_SYS_PLL_DCO 85
#define CLKID_FIXED_PLL_DCO 86
#define CLKID_GP0_PLL_DCO 87
#define CLKID_HIFI_PLL_DCO 88
#define CLKID_PCIE_PLL_DCO 89
#define CLKID_PCIE_PLL_OD 90
#define NR_CLKS 85
#define NR_CLKS 91
/* include the CLKIDs that have been made part of the DT binding */
#include <dt-bindings/clock/axg-clkc.h>

View File

@@ -11,15 +11,19 @@
* In the most basic form, a Meson PLL is composed as follows:
*
* PLL
* +------------------------------+
* | |
* in -----[ /N ]---[ *M ]---[ >>OD ]----->> out
* | ^ ^ |
* +------------------------------+
* | |
* FREF VCO
* +--------------------------------+
* | |
* | +--+ |
* in >>-----[ /N ]--->| | +-----+ |
* | | |------| DCO |---->> out
* | +--------->| | +--v--+ |
* | | +--+ | |
* | | | |
* | +--[ *(M + (F/Fmax) ]<--+ |
* | |
* +--------------------------------+
*
* out = in * (m + frac / frac_max) / (n << sum(ods))
* out = in * (m + frac / frac_max) / n
*/
#include <linux/clk-provider.h>
@@ -41,12 +45,11 @@ meson_clk_pll_data(struct clk_regmap *clk)
}
static unsigned long __pll_params_to_rate(unsigned long parent_rate,
const struct pll_rate_table *pllt,
const struct pll_params_table *pllt,
u16 frac,
struct meson_clk_pll_data *pll)
{
u64 rate = (u64)parent_rate * pllt->m;
unsigned int od = pllt->od + pllt->od2 + pllt->od3;
if (frac && MESON_PARM_APPLICABLE(&pll->frac)) {
u64 frac_rate = (u64)parent_rate * frac;
@@ -55,7 +58,7 @@ static unsigned long __pll_params_to_rate(unsigned long parent_rate,
(1 << pll->frac.width));
}
return DIV_ROUND_UP_ULL(rate, pllt->n << od);
return DIV_ROUND_UP_ULL(rate, pllt->n);
}
static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
@@ -63,20 +66,11 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
struct pll_rate_table pllt;
struct pll_params_table pllt;
u16 frac;
pllt.n = meson_parm_read(clk->map, &pll->n);
pllt.m = meson_parm_read(clk->map, &pll->m);
pllt.od = meson_parm_read(clk->map, &pll->od);
pllt.od2 = MESON_PARM_APPLICABLE(&pll->od2) ?
meson_parm_read(clk->map, &pll->od2) :
0;
pllt.od3 = MESON_PARM_APPLICABLE(&pll->od3) ?
meson_parm_read(clk->map, &pll->od3) :
0;
frac = MESON_PARM_APPLICABLE(&pll->frac) ?
meson_parm_read(clk->map, &pll->frac) :
@@ -87,14 +81,12 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
static u16 __pll_params_with_frac(unsigned long rate,
unsigned long parent_rate,
const struct pll_rate_table *pllt,
const struct pll_params_table *pllt,
struct meson_clk_pll_data *pll)
{
u16 frac_max = (1 << pll->frac.width);
u64 val = (u64)rate * pllt->n;
val <<= pllt->od + pllt->od2 + pllt->od3;
if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST)
val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate);
else
@@ -105,29 +97,50 @@ static u16 __pll_params_with_frac(unsigned long rate,
return min((u16)val, (u16)(frac_max - 1));
}
static const struct pll_rate_table *
static bool meson_clk_pll_is_better(unsigned long rate,
unsigned long best,
unsigned long now,
struct meson_clk_pll_data *pll)
{
if (!(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) ||
MESON_PARM_APPLICABLE(&pll->frac)) {
/* Round down */
if (now < rate && best < now)
return true;
} else {
/* Round Closest */
if (abs(now - rate) < abs(best - rate))
return true;
}
return false;
}
static const struct pll_params_table *
meson_clk_get_pll_settings(unsigned long rate,
unsigned long parent_rate,
struct meson_clk_pll_data *pll)
{
const struct pll_rate_table *table = pll->table;
unsigned int i = 0;
const struct pll_params_table *table = pll->table;
unsigned long best = 0, now = 0;
unsigned int i, best_i = 0;
if (!table)
return NULL;
/* Find the first table element exceeding rate */
while (table[i].rate && table[i].rate <= rate)
i++;
for (i = 0; table[i].n; i++) {
now = __pll_params_to_rate(parent_rate, &table[i], 0, pll);
if (i != 0) {
if (MESON_PARM_APPLICABLE(&pll->frac) ||
!(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) ||
(abs(rate - table[i - 1].rate) <
abs(rate - table[i].rate)))
i--;
/* If we get an exact match, don't bother any further */
if (now == rate) {
return &table[i];
} else if (meson_clk_pll_is_better(rate, best, now, pll)) {
best = now;
best_i = i;
}
}
return (struct pll_rate_table *)&table[i];
return (struct pll_params_table *)&table[best_i];
}
static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -135,16 +148,18 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
const struct pll_rate_table *pllt =
meson_clk_get_pll_settings(rate, pll);
const struct pll_params_table *pllt =
meson_clk_get_pll_settings(rate, *parent_rate, pll);
unsigned long round;
u16 frac;
if (!pllt)
return meson_clk_pll_recalc_rate(hw, *parent_rate);
if (!MESON_PARM_APPLICABLE(&pll->frac)
|| rate == pllt->rate)
return pllt->rate;
round = __pll_params_to_rate(*parent_rate, pllt, 0, pll);
if (!MESON_PARM_APPLICABLE(&pll->frac) || rate == round)
return round;
/*
* The rate provided by the setting is not an exact match, let's
@@ -185,12 +200,45 @@ static void meson_clk_pll_init(struct clk_hw *hw)
}
}
static int meson_clk_pll_enable(struct clk_hw *hw)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
/* Make sure the pll is in reset */
meson_parm_write(clk->map, &pll->rst, 1);
/* Enable the pll */
meson_parm_write(clk->map, &pll->en, 1);
/* Take the pll out reset */
meson_parm_write(clk->map, &pll->rst, 0);
if (meson_clk_pll_wait_lock(hw))
return -EIO;
return 0;
}
static void meson_clk_pll_disable(struct clk_hw *hw)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
/* Put the pll is in reset */
meson_parm_write(clk->map, &pll->rst, 1);
/* Disable the pll */
meson_parm_write(clk->map, &pll->en, 0);
}
static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_regmap *clk = to_clk_regmap(hw);
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
const struct pll_rate_table *pllt;
const struct pll_params_table *pllt;
unsigned int enabled;
unsigned long old_rate;
u16 frac = 0;
@@ -199,32 +247,28 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
old_rate = rate;
pllt = meson_clk_get_pll_settings(rate, pll);
pllt = meson_clk_get_pll_settings(rate, parent_rate, pll);
if (!pllt)
return -EINVAL;
/* Put the pll in reset to write the params */
meson_parm_write(clk->map, &pll->rst, 1);
enabled = meson_parm_read(clk->map, &pll->en);
if (enabled)
meson_clk_pll_disable(hw);
meson_parm_write(clk->map, &pll->n, pllt->n);
meson_parm_write(clk->map, &pll->m, pllt->m);
meson_parm_write(clk->map, &pll->od, pllt->od);
if (MESON_PARM_APPLICABLE(&pll->od2))
meson_parm_write(clk->map, &pll->od2, pllt->od2);
if (MESON_PARM_APPLICABLE(&pll->od3))
meson_parm_write(clk->map, &pll->od3, pllt->od3);
if (MESON_PARM_APPLICABLE(&pll->frac)) {
frac = __pll_params_with_frac(rate, parent_rate, pllt, pll);
meson_parm_write(clk->map, &pll->frac, frac);
}
/* make sure the reset is cleared at this point */
meson_parm_write(clk->map, &pll->rst, 0);
/* If the pll is stopped, bail out now */
if (!enabled)
return 0;
if (meson_clk_pll_wait_lock(hw)) {
if (meson_clk_pll_enable(hw)) {
pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
__func__, old_rate);
/*
@@ -244,6 +288,8 @@ const struct clk_ops meson_clk_pll_ops = {
.recalc_rate = meson_clk_pll_recalc_rate,
.round_rate = meson_clk_pll_round_rate,
.set_rate = meson_clk_pll_set_rate,
.enable = meson_clk_pll_enable,
.disable = meson_clk_pll_disable
};
const struct clk_ops meson_clk_pll_ro_ops = {

View File

@@ -43,37 +43,29 @@ static inline void meson_parm_write(struct regmap *map, struct parm *p,
}
struct pll_rate_table {
unsigned long rate;
struct pll_params_table {
u16 m;
u16 n;
u16 od;
u16 od2;
u16 od3;
};
#define PLL_RATE(_r, _m, _n, _od) \
#define PLL_PARAMS(_m, _n) \
{ \
.rate = (_r), \
.m = (_m), \
.n = (_n), \
.od = (_od), \
}
#define CLK_MESON_PLL_ROUND_CLOSEST BIT(0)
struct meson_clk_pll_data {
struct parm en;
struct parm m;
struct parm n;
struct parm frac;
struct parm od;
struct parm od2;
struct parm od3;
struct parm l;
struct parm rst;
const struct reg_sequence *init_regs;
unsigned int init_count;
const struct pll_rate_table *table;
const struct pll_params_table *table;
u8 flags;
};

View File

@@ -18,165 +18,77 @@
static DEFINE_SPINLOCK(meson_clk_lock);
static const struct pll_rate_table gxbb_gp0_pll_rate_table[] = {
PLL_RATE(96000000, 32, 1, 3),
PLL_RATE(99000000, 33, 1, 3),
PLL_RATE(102000000, 34, 1, 3),
PLL_RATE(105000000, 35, 1, 3),
PLL_RATE(108000000, 36, 1, 3),
PLL_RATE(111000000, 37, 1, 3),
PLL_RATE(114000000, 38, 1, 3),
PLL_RATE(117000000, 39, 1, 3),
PLL_RATE(120000000, 40, 1, 3),
PLL_RATE(123000000, 41, 1, 3),
PLL_RATE(126000000, 42, 1, 3),
PLL_RATE(129000000, 43, 1, 3),
PLL_RATE(132000000, 44, 1, 3),
PLL_RATE(135000000, 45, 1, 3),
PLL_RATE(138000000, 46, 1, 3),
PLL_RATE(141000000, 47, 1, 3),
PLL_RATE(144000000, 48, 1, 3),
PLL_RATE(147000000, 49, 1, 3),
PLL_RATE(150000000, 50, 1, 3),
PLL_RATE(153000000, 51, 1, 3),
PLL_RATE(156000000, 52, 1, 3),
PLL_RATE(159000000, 53, 1, 3),
PLL_RATE(162000000, 54, 1, 3),
PLL_RATE(165000000, 55, 1, 3),
PLL_RATE(168000000, 56, 1, 3),
PLL_RATE(171000000, 57, 1, 3),
PLL_RATE(174000000, 58, 1, 3),
PLL_RATE(177000000, 59, 1, 3),
PLL_RATE(180000000, 60, 1, 3),
PLL_RATE(183000000, 61, 1, 3),
PLL_RATE(186000000, 62, 1, 3),
PLL_RATE(192000000, 32, 1, 2),
PLL_RATE(198000000, 33, 1, 2),
PLL_RATE(204000000, 34, 1, 2),
PLL_RATE(210000000, 35, 1, 2),
PLL_RATE(216000000, 36, 1, 2),
PLL_RATE(222000000, 37, 1, 2),
PLL_RATE(228000000, 38, 1, 2),
PLL_RATE(234000000, 39, 1, 2),
PLL_RATE(240000000, 40, 1, 2),
PLL_RATE(246000000, 41, 1, 2),
PLL_RATE(252000000, 42, 1, 2),
PLL_RATE(258000000, 43, 1, 2),
PLL_RATE(264000000, 44, 1, 2),
PLL_RATE(270000000, 45, 1, 2),
PLL_RATE(276000000, 46, 1, 2),
PLL_RATE(282000000, 47, 1, 2),
PLL_RATE(288000000, 48, 1, 2),
PLL_RATE(294000000, 49, 1, 2),
PLL_RATE(300000000, 50, 1, 2),
PLL_RATE(306000000, 51, 1, 2),
PLL_RATE(312000000, 52, 1, 2),
PLL_RATE(318000000, 53, 1, 2),
PLL_RATE(324000000, 54, 1, 2),
PLL_RATE(330000000, 55, 1, 2),
PLL_RATE(336000000, 56, 1, 2),
PLL_RATE(342000000, 57, 1, 2),
PLL_RATE(348000000, 58, 1, 2),
PLL_RATE(354000000, 59, 1, 2),
PLL_RATE(360000000, 60, 1, 2),
PLL_RATE(366000000, 61, 1, 2),
PLL_RATE(372000000, 62, 1, 2),
PLL_RATE(384000000, 32, 1, 1),
PLL_RATE(396000000, 33, 1, 1),
PLL_RATE(408000000, 34, 1, 1),
PLL_RATE(420000000, 35, 1, 1),
PLL_RATE(432000000, 36, 1, 1),
PLL_RATE(444000000, 37, 1, 1),
PLL_RATE(456000000, 38, 1, 1),
PLL_RATE(468000000, 39, 1, 1),
PLL_RATE(480000000, 40, 1, 1),
PLL_RATE(492000000, 41, 1, 1),
PLL_RATE(504000000, 42, 1, 1),
PLL_RATE(516000000, 43, 1, 1),
PLL_RATE(528000000, 44, 1, 1),
PLL_RATE(540000000, 45, 1, 1),
PLL_RATE(552000000, 46, 1, 1),
PLL_RATE(564000000, 47, 1, 1),
PLL_RATE(576000000, 48, 1, 1),
PLL_RATE(588000000, 49, 1, 1),
PLL_RATE(600000000, 50, 1, 1),
PLL_RATE(612000000, 51, 1, 1),
PLL_RATE(624000000, 52, 1, 1),
PLL_RATE(636000000, 53, 1, 1),
PLL_RATE(648000000, 54, 1, 1),
PLL_RATE(660000000, 55, 1, 1),
PLL_RATE(672000000, 56, 1, 1),
PLL_RATE(684000000, 57, 1, 1),
PLL_RATE(696000000, 58, 1, 1),
PLL_RATE(708000000, 59, 1, 1),
PLL_RATE(720000000, 60, 1, 1),
PLL_RATE(732000000, 61, 1, 1),
PLL_RATE(744000000, 62, 1, 1),
PLL_RATE(768000000, 32, 1, 0),
PLL_RATE(792000000, 33, 1, 0),
PLL_RATE(816000000, 34, 1, 0),
PLL_RATE(840000000, 35, 1, 0),
PLL_RATE(864000000, 36, 1, 0),
PLL_RATE(888000000, 37, 1, 0),
PLL_RATE(912000000, 38, 1, 0),
PLL_RATE(936000000, 39, 1, 0),
PLL_RATE(960000000, 40, 1, 0),
PLL_RATE(984000000, 41, 1, 0),
PLL_RATE(1008000000, 42, 1, 0),
PLL_RATE(1032000000, 43, 1, 0),
PLL_RATE(1056000000, 44, 1, 0),
PLL_RATE(1080000000, 45, 1, 0),
PLL_RATE(1104000000, 46, 1, 0),
PLL_RATE(1128000000, 47, 1, 0),
PLL_RATE(1152000000, 48, 1, 0),
PLL_RATE(1176000000, 49, 1, 0),
PLL_RATE(1200000000, 50, 1, 0),
PLL_RATE(1224000000, 51, 1, 0),
PLL_RATE(1248000000, 52, 1, 0),
PLL_RATE(1272000000, 53, 1, 0),
PLL_RATE(1296000000, 54, 1, 0),
PLL_RATE(1320000000, 55, 1, 0),
PLL_RATE(1344000000, 56, 1, 0),
PLL_RATE(1368000000, 57, 1, 0),
PLL_RATE(1392000000, 58, 1, 0),
PLL_RATE(1416000000, 59, 1, 0),
PLL_RATE(1440000000, 60, 1, 0),
PLL_RATE(1464000000, 61, 1, 0),
PLL_RATE(1488000000, 62, 1, 0),
static const struct pll_params_table gxbb_gp0_pll_params_table[] = {
PLL_PARAMS(32, 1),
PLL_PARAMS(33, 1),
PLL_PARAMS(34, 1),
PLL_PARAMS(35, 1),
PLL_PARAMS(36, 1),
PLL_PARAMS(37, 1),
PLL_PARAMS(38, 1),
PLL_PARAMS(39, 1),
PLL_PARAMS(40, 1),
PLL_PARAMS(41, 1),
PLL_PARAMS(42, 1),
PLL_PARAMS(43, 1),
PLL_PARAMS(44, 1),
PLL_PARAMS(45, 1),
PLL_PARAMS(46, 1),
PLL_PARAMS(47, 1),
PLL_PARAMS(48, 1),
PLL_PARAMS(49, 1),
PLL_PARAMS(50, 1),
PLL_PARAMS(51, 1),
PLL_PARAMS(52, 1),
PLL_PARAMS(53, 1),
PLL_PARAMS(54, 1),
PLL_PARAMS(55, 1),
PLL_PARAMS(56, 1),
PLL_PARAMS(57, 1),
PLL_PARAMS(58, 1),
PLL_PARAMS(59, 1),
PLL_PARAMS(60, 1),
PLL_PARAMS(61, 1),
PLL_PARAMS(62, 1),
{ /* sentinel */ },
};
static const struct pll_rate_table gxl_gp0_pll_rate_table[] = {
PLL_RATE(504000000, 42, 1, 1),
PLL_RATE(516000000, 43, 1, 1),
PLL_RATE(528000000, 44, 1, 1),
PLL_RATE(540000000, 45, 1, 1),
PLL_RATE(552000000, 46, 1, 1),
PLL_RATE(564000000, 47, 1, 1),
PLL_RATE(576000000, 48, 1, 1),
PLL_RATE(588000000, 49, 1, 1),
PLL_RATE(600000000, 50, 1, 1),
PLL_RATE(612000000, 51, 1, 1),
PLL_RATE(624000000, 52, 1, 1),
PLL_RATE(636000000, 53, 1, 1),
PLL_RATE(648000000, 54, 1, 1),
PLL_RATE(660000000, 55, 1, 1),
PLL_RATE(672000000, 56, 1, 1),
PLL_RATE(684000000, 57, 1, 1),
PLL_RATE(696000000, 58, 1, 1),
PLL_RATE(708000000, 59, 1, 1),
PLL_RATE(720000000, 60, 1, 1),
PLL_RATE(732000000, 61, 1, 1),
PLL_RATE(744000000, 62, 1, 1),
PLL_RATE(756000000, 63, 1, 1),
PLL_RATE(768000000, 64, 1, 1),
PLL_RATE(780000000, 65, 1, 1),
PLL_RATE(792000000, 66, 1, 1),
static const struct pll_params_table gxl_gp0_pll_params_table[] = {
PLL_PARAMS(42, 1),
PLL_PARAMS(43, 1),
PLL_PARAMS(44, 1),
PLL_PARAMS(45, 1),
PLL_PARAMS(46, 1),
PLL_PARAMS(47, 1),
PLL_PARAMS(48, 1),
PLL_PARAMS(49, 1),
PLL_PARAMS(50, 1),
PLL_PARAMS(51, 1),
PLL_PARAMS(52, 1),
PLL_PARAMS(53, 1),
PLL_PARAMS(54, 1),
PLL_PARAMS(55, 1),
PLL_PARAMS(56, 1),
PLL_PARAMS(57, 1),
PLL_PARAMS(58, 1),
PLL_PARAMS(59, 1),
PLL_PARAMS(60, 1),
PLL_PARAMS(61, 1),
PLL_PARAMS(62, 1),
PLL_PARAMS(63, 1),
PLL_PARAMS(64, 1),
PLL_PARAMS(65, 1),
PLL_PARAMS(66, 1),
{ /* sentinel */ },
};
static struct clk_regmap gxbb_fixed_pll = {
static struct clk_regmap gxbb_fixed_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = HHI_MPLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_MPLL_CNTL,
.shift = 0,
@@ -187,11 +99,6 @@ static struct clk_regmap gxbb_fixed_pll = {
.shift = 9,
.width = 5,
},
.od = {
.reg_off = HHI_MPLL_CNTL,
.shift = 16,
.width = 2,
},
.frac = {
.reg_off = HHI_MPLL_CNTL2,
.shift = 0,
@@ -209,11 +116,29 @@ static struct clk_regmap gxbb_fixed_pll = {
},
},
.hw.init = &(struct clk_init_data){
.name = "fixed_pll",
.name = "fixed_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxbb_fixed_pll = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_MPLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "fixed_pll",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "fixed_pll_dco" },
.num_parents = 1,
/*
* This clock won't ever change at runtime so
* CLK_SET_RATE_PARENT is not required
*/
},
};
@@ -228,8 +153,13 @@ static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = {
},
};
static struct clk_regmap gxbb_hdmi_pll = {
static struct clk_regmap gxbb_hdmi_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = HHI_HDMI_PLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_HDMI_PLL_CNTL,
.shift = 0,
@@ -245,21 +175,6 @@ static struct clk_regmap gxbb_hdmi_pll = {
.shift = 0,
.width = 12,
},
.od = {
.reg_off = HHI_HDMI_PLL_CNTL2,
.shift = 16,
.width = 2,
},
.od2 = {
.reg_off = HHI_HDMI_PLL_CNTL2,
.shift = 22,
.width = 2,
},
.od3 = {
.reg_off = HHI_HDMI_PLL_CNTL2,
.shift = 18,
.width = 2,
},
.l = {
.reg_off = HHI_HDMI_PLL_CNTL,
.shift = 31,
@@ -272,106 +187,163 @@ static struct clk_regmap gxbb_hdmi_pll = {
},
},
.hw.init = &(struct clk_init_data){
.name = "hdmi_pll",
.name = "hdmi_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "hdmi_pll_pre_mult" },
.num_parents = 1,
/*
* Display directly handle hdmi pll registers ATM, we need
* NOCACHE to keep our view of the clock as accurate as possible
*/
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxbb_hdmi_pll_od = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_HDMI_PLL_CNTL2,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "hdmi_pll_od",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "hdmi_pll_dco" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap gxbb_hdmi_pll_od2 = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_HDMI_PLL_CNTL2,
.shift = 22,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "hdmi_pll_od2",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "hdmi_pll_od" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap gxbb_hdmi_pll = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_HDMI_PLL_CNTL2,
.shift = 18,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "hdmi_pll",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "hdmi_pll_od2" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap gxl_hdmi_pll_od = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_HDMI_PLL_CNTL + 8,
.shift = 21,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "hdmi_pll_od",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "hdmi_pll_dco" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap gxl_hdmi_pll_od2 = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_HDMI_PLL_CNTL + 8,
.shift = 23,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "hdmi_pll_od2",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "hdmi_pll_od" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap gxl_hdmi_pll = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_HDMI_PLL_CNTL + 8,
.shift = 19,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "hdmi_pll",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "hdmi_pll_od2" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap gxbb_sys_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_HDMI_PLL_CNTL,
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 0,
.width = 9,
},
.n = {
.reg_off = HHI_HDMI_PLL_CNTL,
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 9,
.width = 5,
},
.frac = {
/*
* On gxl, there is a register shift due to
* HHI_HDMI_PLL_CNTL1 which does not exist on gxbb,
* so we compute the register offset based on the PLL
* base to get it right
*/
.reg_off = HHI_HDMI_PLL_CNTL + 4,
.shift = 0,
.width = 12,
},
.od = {
.reg_off = HHI_HDMI_PLL_CNTL + 8,
.shift = 21,
.width = 2,
},
.od2 = {
.reg_off = HHI_HDMI_PLL_CNTL + 8,
.shift = 23,
.width = 2,
},
.od3 = {
.reg_off = HHI_HDMI_PLL_CNTL + 8,
.shift = 19,
.width = 2,
},
.l = {
.reg_off = HHI_HDMI_PLL_CNTL,
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_HDMI_PLL_CNTL,
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 29,
.width = 1,
},
},
.hw.init = &(struct clk_init_data){
.name = "hdmi_pll",
.name = "sys_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxbb_sys_pll = {
.data = &(struct meson_clk_pll_data){
.m = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 0,
.width = 9,
},
.n = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 9,
.width = 5,
},
.od = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 10,
.width = 2,
},
.l = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 29,
.width = 1,
},
.data = &(struct clk_regmap_div_data){
.offset = HHI_SYS_PLL_CNTL,
.shift = 10,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "sys_pll",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "sys_pll_dco" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
.flags = CLK_SET_RATE_PARENT,
},
};
@@ -379,11 +351,15 @@ static const struct reg_sequence gxbb_gp0_init_regs[] = {
{ .reg = HHI_GP0_PLL_CNTL2, .def = 0x69c80000 },
{ .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a5590c4 },
{ .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d },
{ .reg = HHI_GP0_PLL_CNTL, .def = 0x4a000228 },
};
static struct clk_regmap gxbb_gp0_pll = {
static struct clk_regmap gxbb_gp0_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 0,
@@ -394,11 +370,6 @@ static struct clk_regmap gxbb_gp0_pll = {
.shift = 9,
.width = 5,
},
.od = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 16,
.width = 2,
},
.l = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 31,
@@ -409,16 +380,15 @@ static struct clk_regmap gxbb_gp0_pll = {
.shift = 29,
.width = 1,
},
.table = gxbb_gp0_pll_rate_table,
.table = gxbb_gp0_pll_params_table,
.init_regs = gxbb_gp0_init_regs,
.init_count = ARRAY_SIZE(gxbb_gp0_init_regs),
},
.hw.init = &(struct clk_init_data){
.name = "gp0_pll",
.name = "gp0_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
@@ -428,11 +398,15 @@ static const struct reg_sequence gxl_gp0_init_regs[] = {
{ .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 },
{ .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d },
{ .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 },
{ .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 },
};
static struct clk_regmap gxl_gp0_pll = {
static struct clk_regmap gxl_gp0_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 0,
@@ -443,11 +417,6 @@ static struct clk_regmap gxl_gp0_pll = {
.shift = 9,
.width = 5,
},
.od = {
.reg_off = HHI_GP0_PLL_CNTL,
.shift = 16,
.width = 2,
},
.frac = {
.reg_off = HHI_GP0_PLL_CNTL1,
.shift = 0,
@@ -463,16 +432,31 @@ static struct clk_regmap gxl_gp0_pll = {
.shift = 29,
.width = 1,
},
.table = gxl_gp0_pll_rate_table,
.table = gxl_gp0_pll_params_table,
.init_regs = gxl_gp0_init_regs,
.init_count = ARRAY_SIZE(gxl_gp0_init_regs),
},
.hw.init = &(struct clk_init_data){
.name = "gp0_pll",
.name = "gp0_pll_dco",
.ops = &meson_clk_pll_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap gxbb_gp0_pll = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_GP0_PLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "gp0_pll",
.ops = &clk_regmap_divider_ops,
.parent_names = (const char *[]){ "gp0_pll_dco" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
@@ -1933,6 +1917,12 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
[CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw,
[CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw,
[CLKID_GEN_CLK] = &gxbb_gen_clk.hw,
[CLKID_FIXED_PLL_DCO] = &gxbb_fixed_pll_dco.hw,
[CLKID_HDMI_PLL_DCO] = &gxbb_hdmi_pll_dco.hw,
[CLKID_HDMI_PLL_OD] = &gxbb_hdmi_pll_od.hw,
[CLKID_HDMI_PLL_OD2] = &gxbb_hdmi_pll_od2.hw,
[CLKID_SYS_PLL_DCO] = &gxbb_sys_pll_dco.hw,
[CLKID_GP0_PLL_DCO] = &gxbb_gp0_pll_dco.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
@@ -1948,7 +1938,7 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
[CLKID_FCLK_DIV4] = &gxbb_fclk_div4.hw,
[CLKID_FCLK_DIV5] = &gxbb_fclk_div5.hw,
[CLKID_FCLK_DIV7] = &gxbb_fclk_div7.hw,
[CLKID_GP0_PLL] = &gxl_gp0_pll.hw,
[CLKID_GP0_PLL] = &gxbb_gp0_pll.hw,
[CLKID_MPEG_SEL] = &gxbb_mpeg_clk_sel.hw,
[CLKID_MPEG_DIV] = &gxbb_mpeg_clk_div.hw,
[CLKID_CLK81] = &gxbb_clk81.hw,
@@ -2098,19 +2088,29 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
[CLKID_GEN_CLK_SEL] = &gxbb_gen_clk_sel.hw,
[CLKID_GEN_CLK_DIV] = &gxbb_gen_clk_div.hw,
[CLKID_GEN_CLK] = &gxbb_gen_clk.hw,
[CLKID_FIXED_PLL_DCO] = &gxbb_fixed_pll_dco.hw,
[CLKID_HDMI_PLL_DCO] = &gxbb_hdmi_pll_dco.hw,
[CLKID_HDMI_PLL_OD] = &gxl_hdmi_pll_od.hw,
[CLKID_HDMI_PLL_OD2] = &gxl_hdmi_pll_od2.hw,
[CLKID_SYS_PLL_DCO] = &gxbb_sys_pll_dco.hw,
[CLKID_GP0_PLL_DCO] = &gxl_gp0_pll_dco.hw,
[NR_CLKS] = NULL,
},
.num = NR_CLKS,
};
static struct clk_regmap *const gxbb_clk_regmaps[] = {
&gxbb_gp0_pll,
&gxbb_gp0_pll_dco,
&gxbb_hdmi_pll,
&gxbb_hdmi_pll_od,
&gxbb_hdmi_pll_od2,
};
static struct clk_regmap *const gxl_clk_regmaps[] = {
&gxl_gp0_pll,
&gxl_gp0_pll_dco,
&gxl_hdmi_pll,
&gxl_hdmi_pll_od,
&gxl_hdmi_pll_od2,
};
static struct clk_regmap *const gx_clk_regmaps[] = {
@@ -2265,6 +2265,10 @@ static struct clk_regmap *const gx_clk_regmaps[] = {
&gxbb_gen_clk_sel,
&gxbb_gen_clk_div,
&gxbb_gen_clk,
&gxbb_fixed_pll_dco,
&gxbb_hdmi_pll_dco,
&gxbb_sys_pll_dco,
&gxbb_gp0_pll,
};
struct clkc_data {

View File

@@ -159,8 +159,14 @@
#define CLKID_VDEC_HEVC_DIV 155
#define CLKID_GEN_CLK_SEL 157
#define CLKID_GEN_CLK_DIV 158
#define CLKID_FIXED_PLL_DCO 160
#define CLKID_HDMI_PLL_DCO 161
#define CLKID_HDMI_PLL_OD 162
#define CLKID_HDMI_PLL_OD2 163
#define CLKID_SYS_PLL_DCO 164
#define CLKID_GP0_PLL_DCO 165
#define NR_CLKS 160
#define NR_CLKS 166
/* include the CLKIDs that have been made part of the DT binding */
#include <dt-bindings/clock/gxbb-clkc.h>

View File

@@ -11,7 +11,6 @@
#include <linux/clk-provider.h>
#include <linux/init.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <linux/regmap.h>
@@ -22,66 +21,27 @@
static DEFINE_SPINLOCK(meson_clk_lock);
static void __iomem *clk_base;
struct meson8b_clk_reset {
struct reset_controller_dev reset;
void __iomem *base;
struct regmap *regmap;
};
static const struct pll_rate_table sys_pll_rate_table[] = {
PLL_RATE(312000000, 52, 1, 2),
PLL_RATE(336000000, 56, 1, 2),
PLL_RATE(360000000, 60, 1, 2),
PLL_RATE(384000000, 64, 1, 2),
PLL_RATE(408000000, 68, 1, 2),
PLL_RATE(432000000, 72, 1, 2),
PLL_RATE(456000000, 76, 1, 2),
PLL_RATE(480000000, 80, 1, 2),
PLL_RATE(504000000, 84, 1, 2),
PLL_RATE(528000000, 88, 1, 2),
PLL_RATE(552000000, 92, 1, 2),
PLL_RATE(576000000, 96, 1, 2),
PLL_RATE(600000000, 50, 1, 1),
PLL_RATE(624000000, 52, 1, 1),
PLL_RATE(648000000, 54, 1, 1),
PLL_RATE(672000000, 56, 1, 1),
PLL_RATE(696000000, 58, 1, 1),
PLL_RATE(720000000, 60, 1, 1),
PLL_RATE(744000000, 62, 1, 1),
PLL_RATE(768000000, 64, 1, 1),
PLL_RATE(792000000, 66, 1, 1),
PLL_RATE(816000000, 68, 1, 1),
PLL_RATE(840000000, 70, 1, 1),
PLL_RATE(864000000, 72, 1, 1),
PLL_RATE(888000000, 74, 1, 1),
PLL_RATE(912000000, 76, 1, 1),
PLL_RATE(936000000, 78, 1, 1),
PLL_RATE(960000000, 80, 1, 1),
PLL_RATE(984000000, 82, 1, 1),
PLL_RATE(1008000000, 84, 1, 1),
PLL_RATE(1032000000, 86, 1, 1),
PLL_RATE(1056000000, 88, 1, 1),
PLL_RATE(1080000000, 90, 1, 1),
PLL_RATE(1104000000, 92, 1, 1),
PLL_RATE(1128000000, 94, 1, 1),
PLL_RATE(1152000000, 96, 1, 1),
PLL_RATE(1176000000, 98, 1, 1),
PLL_RATE(1200000000, 50, 1, 0),
PLL_RATE(1224000000, 51, 1, 0),
PLL_RATE(1248000000, 52, 1, 0),
PLL_RATE(1272000000, 53, 1, 0),
PLL_RATE(1296000000, 54, 1, 0),
PLL_RATE(1320000000, 55, 1, 0),
PLL_RATE(1344000000, 56, 1, 0),
PLL_RATE(1368000000, 57, 1, 0),
PLL_RATE(1392000000, 58, 1, 0),
PLL_RATE(1416000000, 59, 1, 0),
PLL_RATE(1440000000, 60, 1, 0),
PLL_RATE(1464000000, 61, 1, 0),
PLL_RATE(1488000000, 62, 1, 0),
PLL_RATE(1512000000, 63, 1, 0),
PLL_RATE(1536000000, 64, 1, 0),
static const struct pll_params_table sys_pll_params_table[] = {
PLL_PARAMS(50, 1),
PLL_PARAMS(51, 1),
PLL_PARAMS(52, 1),
PLL_PARAMS(53, 1),
PLL_PARAMS(54, 1),
PLL_PARAMS(55, 1),
PLL_PARAMS(56, 1),
PLL_PARAMS(57, 1),
PLL_PARAMS(58, 1),
PLL_PARAMS(59, 1),
PLL_PARAMS(60, 1),
PLL_PARAMS(61, 1),
PLL_PARAMS(62, 1),
PLL_PARAMS(63, 1),
PLL_PARAMS(64, 1),
{ /* sentinel */ },
};
@@ -94,8 +54,13 @@ static struct clk_fixed_rate meson8b_xtal = {
},
};
static struct clk_regmap meson8b_fixed_pll = {
static struct clk_regmap meson8b_fixed_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = HHI_MPLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_MPLL_CNTL,
.shift = 0,
@@ -106,11 +71,6 @@ static struct clk_regmap meson8b_fixed_pll = {
.shift = 9,
.width = 5,
},
.od = {
.reg_off = HHI_MPLL_CNTL,
.shift = 16,
.width = 2,
},
.frac = {
.reg_off = HHI_MPLL_CNTL2,
.shift = 0,
@@ -128,86 +88,134 @@ static struct clk_regmap meson8b_fixed_pll = {
},
},
.hw.init = &(struct clk_init_data){
.name = "fixed_pll",
.name = "fixed_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
},
};
static struct clk_regmap meson8b_fixed_pll = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_MPLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "fixed_pll",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "fixed_pll_dco" },
.num_parents = 1,
/*
* This clock won't ever change at runtime so
* CLK_SET_RATE_PARENT is not required
*/
},
};
static struct clk_regmap meson8b_vid_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 0,
.width = 9,
},
.n = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 9,
.width = 5,
},
.l = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 29,
.width = 1,
},
},
.hw.init = &(struct clk_init_data){
.name = "vid_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap meson8b_vid_pll = {
.data = &(struct clk_regmap_div_data){
.offset = HHI_VID_PLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "vid_pll",
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "vid_pll_dco" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
},
};
static struct clk_regmap meson8b_sys_pll_dco = {
.data = &(struct meson_clk_pll_data){
.en = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 30,
.width = 1,
},
.m = {
.reg_off = HHI_VID_PLL_CNTL,
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 0,
.width = 9,
},
.n = {
.reg_off = HHI_VID_PLL_CNTL,
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 9,
.width = 5,
},
.od = {
.reg_off = HHI_VID_PLL_CNTL,
.shift = 16,
.width = 2,
},
.l = {
.reg_off = HHI_VID_PLL_CNTL,
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_VID_PLL_CNTL,
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 29,
.width = 1,
},
.table = sys_pll_params_table,
},
.hw.init = &(struct clk_init_data){
.name = "vid_pll",
.name = "sys_pll_dco",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
},
};
static struct clk_regmap meson8b_sys_pll = {
.data = &(struct meson_clk_pll_data){
.m = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 0,
.width = 9,
},
.n = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 9,
.width = 5,
},
.od = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 16,
.width = 2,
},
.l = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 31,
.width = 1,
},
.rst = {
.reg_off = HHI_SYS_PLL_CNTL,
.shift = 29,
.width = 1,
},
.table = sys_pll_rate_table,
.data = &(struct clk_regmap_div_data){
.offset = HHI_SYS_PLL_CNTL,
.shift = 16,
.width = 2,
.flags = CLK_DIVIDER_POWER_OF_TWO,
},
.hw.init = &(struct clk_init_data){
.name = "sys_pll",
.ops = &meson_clk_pll_ro_ops,
.parent_names = (const char *[]){ "xtal" },
.ops = &clk_regmap_divider_ro_ops,
.parent_names = (const char *[]){ "sys_pll_dco" },
.num_parents = 1,
.flags = CLK_GET_RATE_NOCACHE,
.flags = CLK_SET_RATE_PARENT,
},
};
@@ -879,6 +887,9 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = {
[CLKID_NAND_SEL] = &meson8b_nand_clk_sel.hw,
[CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw,
[CLKID_NAND_CLK] = &meson8b_nand_clk_gate.hw,
[CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw,
[CLKID_PLL_VID_DCO] = &meson8b_vid_pll_dco.hw,
[CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw,
[CLK_NR_CLKS] = NULL,
},
.num = CLK_NR_CLKS,
@@ -987,6 +998,9 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = {
&meson8b_nand_clk_sel,
&meson8b_nand_clk_div,
&meson8b_nand_clk_gate,
&meson8b_fixed_pll_dco,
&meson8b_vid_pll_dco,
&meson8b_sys_pll_dco,
};
static const struct meson8b_clk_reset_line {
@@ -1050,7 +1064,6 @@ static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev,
container_of(rcdev, struct meson8b_clk_reset, reset);
unsigned long flags;
const struct meson8b_clk_reset_line *reset;
u32 val;
if (id >= ARRAY_SIZE(meson8b_clk_reset_bits))
return -EINVAL;
@@ -1059,12 +1072,12 @@ static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev,
spin_lock_irqsave(&meson_clk_lock, flags);
val = readl(meson8b_clk_reset->base + reset->reg);
if (assert)
val |= BIT(reset->bit_idx);
regmap_update_bits(meson8b_clk_reset->regmap, reset->reg,
BIT(reset->bit_idx), BIT(reset->bit_idx));
else
val &= ~BIT(reset->bit_idx);
writel(val, meson8b_clk_reset->base + reset->reg);
regmap_update_bits(meson8b_clk_reset->regmap, reset->reg,
BIT(reset->bit_idx), 0);
spin_unlock_irqrestore(&meson_clk_lock, flags);
@@ -1094,18 +1107,39 @@ static const struct regmap_config clkc_regmap_config = {
.reg_stride = 4,
};
static int meson8b_clkc_probe(struct platform_device *pdev)
static void __init meson8b_clkc_init(struct device_node *np)
{
int ret, i;
struct device *dev = &pdev->dev;
struct meson8b_clk_reset *rstc;
void __iomem *clk_base;
struct regmap *map;
int i, ret;
if (!clk_base)
return -ENXIO;
/* Generic clocks, PLLs and some of the reset-bits */
clk_base = of_iomap(np, 1);
if (!clk_base) {
pr_err("%s: Unable to map clk base\n", __func__);
return;
}
map = devm_regmap_init_mmio(dev, clk_base, &clkc_regmap_config);
map = regmap_init_mmio(NULL, clk_base, &clkc_regmap_config);
if (IS_ERR(map))
return PTR_ERR(map);
return;
rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
if (!rstc)
return;
/* Reset Controller */
rstc->regmap = map;
rstc->reset.ops = &meson8b_clk_reset_ops;
rstc->reset.nr_resets = ARRAY_SIZE(meson8b_clk_reset_bits);
rstc->reset.of_node = np;
ret = reset_controller_register(&rstc->reset);
if (ret) {
pr_err("%s: Failed to register clkc reset controller: %d\n",
__func__, ret);
return;
}
/* Populate regmap for the regmap backed clocks */
for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++)
@@ -1120,64 +1154,20 @@ static int meson8b_clkc_probe(struct platform_device *pdev)
if (!meson8b_hw_onecell_data.hws[i])
continue;
ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[i]);
ret = clk_hw_register(NULL, meson8b_hw_onecell_data.hws[i]);
if (ret)
return ret;
return;
}
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
&meson8b_hw_onecell_data);
}
static const struct of_device_id meson8b_clkc_match_table[] = {
{ .compatible = "amlogic,meson8-clkc" },
{ .compatible = "amlogic,meson8b-clkc" },
{ .compatible = "amlogic,meson8m2-clkc" },
{ }
};
static struct platform_driver meson8b_driver = {
.probe = meson8b_clkc_probe,
.driver = {
.name = "meson8b-clkc",
.of_match_table = meson8b_clkc_match_table,
},
};
builtin_platform_driver(meson8b_driver);
static void __init meson8b_clkc_reset_init(struct device_node *np)
{
struct meson8b_clk_reset *rstc;
int ret;
/* Generic clocks, PLLs and some of the reset-bits */
clk_base = of_iomap(np, 1);
if (!clk_base) {
pr_err("%s: Unable to map clk base\n", __func__);
return;
}
rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
if (!rstc)
return;
/* Reset Controller */
rstc->base = clk_base;
rstc->reset.ops = &meson8b_clk_reset_ops;
rstc->reset.nr_resets = ARRAY_SIZE(meson8b_clk_reset_bits);
rstc->reset.of_node = np;
ret = reset_controller_register(&rstc->reset);
if (ret) {
pr_err("%s: Failed to register clkc reset controller: %d\n",
__func__, ret);
return;
}
ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
&meson8b_hw_onecell_data);
if (ret)
pr_err("%s: failed to register clock provider\n", __func__);
}
CLK_OF_DECLARE_DRIVER(meson8_clkc, "amlogic,meson8-clkc",
meson8b_clkc_reset_init);
meson8b_clkc_init);
CLK_OF_DECLARE_DRIVER(meson8b_clkc, "amlogic,meson8b-clkc",
meson8b_clkc_reset_init);
meson8b_clkc_init);
CLK_OF_DECLARE_DRIVER(meson8m2_clkc, "amlogic,meson8m2-clkc",
meson8b_clkc_reset_init);
meson8b_clkc_init);

View File

@@ -75,8 +75,11 @@
#define CLKID_FCLK_DIV7_DIV 109
#define CLKID_NAND_SEL 110
#define CLKID_NAND_DIV 111
#define CLKID_PLL_FIXED_DCO 113
#define CLKID_PLL_VID_DCO 114
#define CLKID_PLL_SYS_DCO 115
#define CLK_NR_CLKS 113
#define CLK_NR_CLKS 116
/*
* include the CLKID and RESETID that have

View File

@@ -227,8 +227,8 @@ static struct mmp_param_gate_clk apmu_gate_clks[] = {
/* The gate clocks has mux parent. */
{MMP2_CLK_SDH0, "sdh0_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_SDH1, "sdh1_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_SDH1, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_SDH1, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_SDH2, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_SDH3, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock},
{MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock},
{MMP2_CLK_DISP0_SPHY, "disp0_sphy_clk", "disp0_sphy_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1024, 0x1024, 0x0, 0, &disp0_lock},
{MMP2_CLK_DISP1, "disp1_clk", "disp1_div", CLK_SET_RATE_PARENT, APMU_DISP1, 0x1b, 0x1b, 0x0, 0, &disp1_lock},

View File

@@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada AP806 System Controller
*
@@ -5,9 +6,6 @@
*
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#define pr_fmt(fmt) "ap806-system-controller: " fmt
@@ -155,7 +153,6 @@ static int ap806_syscon_common_probe(struct platform_device *pdev,
goto fail4;
}
of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data);
ret = of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data);
if (ret)
goto fail_clk_add;

View File

@@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada 370 SoC clocks
*
@@ -7,9 +8,6 @@
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>

View File

@@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada 375 SoC clocks
*
@@ -7,9 +8,6 @@
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>

View File

@@ -56,6 +56,15 @@
struct clk_periph_driver_data {
struct clk_hw_onecell_data *hw_data;
spinlock_t lock;
void __iomem *reg;
/* Storage registers for suspend/resume operations */
u32 tbg_sel;
u32 div_sel0;
u32 div_sel1;
u32 div_sel2;
u32 clk_sel;
u32 clk_dis;
};
struct clk_double_div {
@@ -672,6 +681,40 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data,
return PTR_ERR_OR_ZERO(*hw);
}
static int __maybe_unused armada_3700_periph_clock_suspend(struct device *dev)
{
struct clk_periph_driver_data *data = dev_get_drvdata(dev);
data->tbg_sel = readl(data->reg + TBG_SEL);
data->div_sel0 = readl(data->reg + DIV_SEL0);
data->div_sel1 = readl(data->reg + DIV_SEL1);
data->div_sel2 = readl(data->reg + DIV_SEL2);
data->clk_sel = readl(data->reg + CLK_SEL);
data->clk_dis = readl(data->reg + CLK_DIS);
return 0;
}
static int __maybe_unused armada_3700_periph_clock_resume(struct device *dev)
{
struct clk_periph_driver_data *data = dev_get_drvdata(dev);
/* Follow the same order than what the Cortex-M3 does (ATF code) */
writel(data->clk_dis, data->reg + CLK_DIS);
writel(data->div_sel0, data->reg + DIV_SEL0);
writel(data->div_sel1, data->reg + DIV_SEL1);
writel(data->div_sel2, data->reg + DIV_SEL2);
writel(data->tbg_sel, data->reg + TBG_SEL);
writel(data->clk_sel, data->reg + CLK_SEL);
return 0;
}
static const struct dev_pm_ops armada_3700_periph_clock_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(armada_3700_periph_clock_suspend,
armada_3700_periph_clock_resume)
};
static int armada_3700_periph_clock_probe(struct platform_device *pdev)
{
struct clk_periph_driver_data *driver_data;
@@ -680,7 +723,6 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
int num_periph = 0, i, ret;
struct resource *res;
void __iomem *reg;
data = of_device_get_match_data(dev);
if (!data)
@@ -689,11 +731,6 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev)
while (data[num_periph].name)
num_periph++;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(dev, res);
if (IS_ERR(reg))
return PTR_ERR(reg);
driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);
if (!driver_data)
return -ENOMEM;
@@ -706,12 +743,16 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev)
return -ENOMEM;
driver_data->hw_data->num = num_periph;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
driver_data->reg = devm_ioremap_resource(dev, res);
if (IS_ERR(driver_data->reg))
return PTR_ERR(driver_data->reg);
spin_lock_init(&driver_data->lock);
for (i = 0; i < num_periph; i++) {
struct clk_hw **hw = &driver_data->hw_data->hws[i];
if (armada_3700_add_composite_clk(&data[i], reg,
if (armada_3700_add_composite_clk(&data[i], driver_data->reg,
&driver_data->lock, dev, hw))
dev_err(dev, "Can't register periph clock %s\n",
data[i].name);
@@ -749,6 +790,7 @@ static struct platform_driver armada_3700_periph_clock_driver = {
.driver = {
.name = "marvell-armada-3700-periph-clock",
.of_match_table = armada_3700_periph_clock_of_match,
.pm = &armada_3700_periph_clock_pm_ops,
},
};

View File

@@ -1,13 +1,10 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Marvell Armada 37xx SoC Time Base Generator clocks
*
* Copyright (C) 2016 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2 or later. This program is licensed "as is"
* without any warranty of any kind, whether express or implied.
*/
#include <linux/clk-provider.h>
@@ -99,12 +96,13 @@ static int armada_3700_tbg_clock_probe(struct platform_device *pdev)
hw_tbg_data->num = NUM_TBG;
platform_set_drvdata(pdev, hw_tbg_data);
parent = devm_clk_get(dev, NULL);
parent = clk_get(dev, NULL);
if (IS_ERR(parent)) {
dev_err(dev, "Could get the clock parent\n");
return -EINVAL;
}
parent_name = __clk_get_name(parent);
clk_put(parent);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(dev, res);

View File

@@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada 37xx SoC xtal clocks
*
@@ -5,9 +6,6 @@
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/clk-provider.h>

View File

@@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada 380/385 SoC clocks
*
@@ -7,9 +8,6 @@
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>

View File

@@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada 39x SoC clocks
*
@@ -8,9 +9,6 @@
* Andrew Lunn <andrew@lunn.ch>
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>

View File

@@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Marvell Armada XP SoC clocks
*
@@ -7,9 +8,6 @@
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>

View File

@@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* MVEBU Core divider clock
*
@@ -5,9 +6,6 @@
*
* Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>

View File

@@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Marvell MVEBU CPU clock handling.
*
@@ -5,9 +6,6 @@
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/slab.h>

View File

@@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Marvell EBU SoC common clock handling
*
@@ -7,9 +8,6 @@
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
* Andrew Lunn <andrew@lunn.ch>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>

Some files were not shown because too many files have changed in this diff Show More