diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-04-05 10:43:32 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-04-05 10:43:32 -0700 |
commit | 347619565197ae0e62a755efc4a80904d66fc0a1 (patch) | |
tree | b2b219d59acec3ec1735e7e598362a3420f193b6 /drivers/clk/at91 | |
parent | aa1a8ce533324d12696a9f4b71dbc5eb561a2e04 (diff) | |
parent | 28ecaf1c30fe3f616eef5ab2dd5990399957234e (diff) | |
download | linux-347619565197ae0e62a755efc4a80904d66fc0a1.tar.gz linux-347619565197ae0e62a755efc4a80904d66fc0a1.tar.bz2 linux-347619565197ae0e62a755efc4a80904d66fc0a1.zip |
Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
Pull clk updates from Stephen Boyd:
"There's not much to see in the core framework this time around.
Instead the majority of the diff is the normal collection of driver
additions for new SoCs and non-critical clk data fixes and updates.
The framework must be middle aged.
The two biggest directories in the diffstat show that the Qualcomm and
Unisoc support added a handful of big drivers for new SoCs but that's
not really the whole story because those new drivers tend to add large
numbers of lines of clk data. There's a handful of AT91 clk drivers
added this time around too and a bunch of improvements to drivers like
the i.MX driver. All around lots of updates and fixes in various clk
drivers which is good to see.
The core framework has only one real major change which has been
baking in next for the past couple months. It fixes the framework so
that it stops caching a clk's phase when the phase clk_op returns an
error. Before this change we would consider some negative errno as a
phase and that just doesn't make sense.
Core:
- Don't show clk phase when it is invalid
New Drivers:
- Add support for Unisoc SC9863A clks
- Qualcomm SM8250 RPMh and MSM8976 RPM clks
- Qualcomm SM8250 Global Clock Controller (GCC) support
- Qualcomm SC7180 Modem Clock Controller (MSS CC) support
- EHRPWM's TimeBase clock(TBCLK) for TI AM654 SoCs
- Support PMC clks on at91sam9n12, at91rm9200, sama5d3, and
at91sam9g45 SoCs
Updates:
- GPU GX GDSC support on Qualcomm sc7180
- Fixes and improvements for the Marvell MMP2/MMP3 SoC clk drivers
- A series from Anson to convert i.MX8 clock bindings to json-schema
- Update i.MX pll14xx driver to include new frequency entries for
pll1443x table, and return error for invalid PLL type
- Add missing of_node_put() call for a number of i.MX clock drivers
- Drop flag CLK_IS_CRITICAL from 'A53_CORE' mux clock, as we already
have the flag on its child cpu clock
- Fix a53 cpu clock for i.MX8 drivers to get it source from ARM PLL
via CORE_SEL slice, and source from A53 CCM clk root when we need
to change ARM PLL frequency. Thus, we can support core running
above 1GHz safely
- Update i.MX pfdv2 driver to check zero rate and use determine_rate
for getting the best rate
- Add CLKO2 for imx8mm, SNVS clock for imx8mn, and PXP clock for
imx7d
- Remove PMC clks from Tegra clk driver
- Improved clock/reset handling for the Renesas R-Car USB2 Clock
Selector
- Conversion to json-schema of the Renesas CPG/MSSR DT bindings
- Add Crypto clocks on Renesas R-Car M3-W/W+, M3-N, E3, and D3
- Add RPC (QSPI/HyperFLASH) clocks on Renesas R-Car H3, M3-W/W+, and
M3-N
- Update Amlogic audio clock gate hierarchy for meson8 and gxbb
- Update Amlogic g12a spicc clock sources
- Support for Ingenic X1000 TCU clks"
* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (146 commits)
clk: sprd: fix to get a correct ibias of pll
dt-bindings: imx8mm-clock: Fix the file path
dt-bindings: imx8mq-clock: Fix the file path
clk: qcom: rpmh: Drop unnecessary semicolons
clk: qcom: rpmh: Simplify clk_rpmh_bcm_send_cmd()
clk: tegra: Use NULL for pointer initialization
clk: sprd: add clocks support for SC9863A
clk: sprd: support to get regmap from parent node
clk: sprd: Add macros for referencing parents without strings
clk: sprd: Add dt-bindings include file for SC9863A
dt-bindings: clk: sprd: add bindings for sc9863a clock controller
dt-bindings: clk: sprd: rename the common file name sprd.txt to SoC specific
clk: sprd: add gate for pll clocks
MAINTAINERS: dt: update reference for arm-integrator.txt
clk: mmp2: Fix bit masks for LCDC I/O and pixel clocks
clk: mmp2: Add clock for fifth SD HCI on MMP3
dt-bindings: marvell,mmp2: Add clock id for the fifth SD HCI on MMP3
clk: mmp2: Add clocks for the thermal sensors
dt-bindings: marvell,mmp2: Add clock ids for the thermal sensors
clk: mmp2: add the GPU clocks
...
Diffstat (limited to 'drivers/clk/at91')
-rw-r--r-- | drivers/clk/at91/Makefile | 4 | ||||
-rw-r--r-- | drivers/clk/at91/at91rm9200.c | 199 | ||||
-rw-r--r-- | drivers/clk/at91/at91sam9g45.c | 220 | ||||
-rw-r--r-- | drivers/clk/at91/at91sam9n12.c | 238 | ||||
-rw-r--r-- | drivers/clk/at91/clk-usb.c | 9 | ||||
-rw-r--r-- | drivers/clk/at91/sam9x60.c | 14 | ||||
-rw-r--r-- | drivers/clk/at91/sama5d3.c | 240 |
7 files changed, 913 insertions, 11 deletions
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 3732241352ce..8b90357f2a93 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -15,7 +15,11 @@ 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_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o +obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o +obj-$(CONFIG_SOC_AT91SAM9) += at91sam9g45.o +obj-$(CONFIG_SOC_AT91SAM9) += at91sam9n12.o at91sam9x5.o obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o +obj-$(CONFIG_SOC_SAMA5D3) += sama5d3.o obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o diff --git a/drivers/clk/at91/at91rm9200.c b/drivers/clk/at91/at91rm9200.c new file mode 100644 index 000000000000..c44a431b6c97 --- /dev/null +++ b/drivers/clk/at91/at91rm9200.c @@ -0,0 +1,199 @@ +// 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; +}; + +static const struct clk_master_characteristics rm9200_mck_characteristics = { + .output = { .min = 0, .max = 80000000 }, + .divisors = { 1, 2, 3, 4 }, +}; + +static u8 rm9200_pll_out[] = { 0, 2 }; + +static const struct clk_range rm9200_pll_outputs[] = { + { .min = 80000000, .max = 160000000 }, + { .min = 150000000, .max = 180000000 }, +}; + +static const struct clk_pll_characteristics rm9200_pll_characteristics = { + .input = { .min = 1000000, .max = 32000000 }, + .num_output = ARRAY_SIZE(rm9200_pll_outputs), + .output = rm9200_pll_outputs, + .out = rm9200_pll_out, +}; + +static const struct sck at91rm9200_systemck[] = { + { .n = "udpck", .p = "usbck", .id = 2 }, + { .n = "uhpck", .p = "usbck", .id = 4 }, + { .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 at91rm9200_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 = "udc_clk", .id = 11 }, + { .n = "twi0_clk", .id = 12 }, + { .n = "spi0_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 = "tc3_clk", .id = 20 }, + { .n = "tc4_clk", .id = 21 }, + { .n = "tc5_clk", .id = 22 }, + { .n = "ohci_clk", .id = 23 }, + { .n = "macb0_clk", .id = 24 }, +}; + +static void __init at91rm9200_pmc_setup(struct device_node *np) +{ + const char *slowxtal_name, *mainxtal_name; + struct pmc_data *at91rm9200_pmc; + u32 usb_div[] = { 1, 2, 0, 0 }; + 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_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 = device_node_to_regmap(np); + if (IS_ERR(regmap)) + return; + + at91rm9200_pmc = pmc_data_allocate(PMC_MAIN + 1, + nck(at91rm9200_systemck), + nck(at91rm9200_periphck), 0); + if (!at91rm9200_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; + + at91rm9200_pmc->chws[PMC_MAIN] = hw; + + hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0, + &at91rm9200_pll_layout, + &rm9200_pll_characteristics); + if (IS_ERR(hw)) + goto err_free; + + hw = at91_clk_register_pll(regmap, "pllbck", "mainck", 1, + &at91rm9200_pll_layout, + &rm9200_pll_characteristics); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = slowxtal_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, + &rm9200_mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + at91rm9200_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] = slowxtal_name; + parent_names[1] = "mainck"; + parent_names[2] = "pllack"; + parent_names[3] = "pllbck"; + for (i = 0; i < 4; 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 < ARRAY_SIZE(at91rm9200_systemck); i++) { + hw = at91_clk_register_system(regmap, at91rm9200_systemck[i].n, + at91rm9200_systemck[i].p, + at91rm9200_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91rm9200_pmc->shws[at91rm9200_systemck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(at91rm9200_periphck); i++) { + hw = at91_clk_register_peripheral(regmap, + at91rm9200_periphck[i].n, + "masterck", + at91rm9200_periphck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91rm9200_pmc->phws[at91rm9200_periphck[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91rm9200_pmc); + + return; + +err_free: + pmc_data_free(at91rm9200_pmc); +} +/* + * While the TCB can be used as the clocksource, the system timer is most likely + * to be used instead. However, the pinctrl driver doesn't support probe + * deferring properly. Once this is fixed, this can be switched to a platform + * driver. + */ +CLK_OF_DECLARE_DRIVER(at91rm9200_pmc, "atmel,at91rm9200-pmc", + at91rm9200_pmc_setup); diff --git a/drivers/clk/at91/at91sam9g45.c b/drivers/clk/at91/at91sam9g45.c new file mode 100644 index 000000000000..38a7d2d2df0c --- /dev/null +++ b/drivers/clk/at91/at91sam9g45.c @@ -0,0 +1,220 @@ +// 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 }, +}; + +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 const 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; +} at91sam9g45_systemck[] = { + { .n = "ddrck", .p = "masterck", .id = 2 }, + { .n = "uhpck", .p = "usbck", .id = 6 }, + { .n = "pck0", .p = "prog0", .id = 8 }, + { .n = "pck1", .p = "prog1", .id = 9 }, +}; + +static const struct clk_pcr_layout at91sam9g45_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(5, 0), + .div_mask = GENMASK(17, 16), +}; + +struct pck { + char *n; + u8 id; +}; + +static const struct pck at91sam9g45_periphck[] = { + { .n = "pioA_clk", .id = 2, }, + { .n = "pioB_clk", .id = 3, }, + { .n = "pioC_clk", .id = 4, }, + { .n = "pioDE_clk", .id = 5, }, + { .n = "trng_clk", .id = 6, }, + { .n = "usart0_clk", .id = 7, }, + { .n = "usart1_clk", .id = 8, }, + { .n = "usart2_clk", .id = 9, }, + { .n = "usart3_clk", .id = 10, }, + { .n = "mci0_clk", .id = 11, }, + { .n = "twi0_clk", .id = 12, }, + { .n = "twi1_clk", .id = 13, }, + { .n = "spi0_clk", .id = 14, }, + { .n = "spi1_clk", .id = 15, }, + { .n = "ssc0_clk", .id = 16, }, + { .n = "ssc1_clk", .id = 17, }, + { .n = "tcb0_clk", .id = 18, }, + { .n = "pwm_clk", .id = 19, }, + { .n = "adc_clk", .id = 20, }, + { .n = "dma0_clk", .id = 21, }, + { .n = "uhphs_clk", .id = 22, }, + { .n = "lcd_clk", .id = 23, }, + { .n = "ac97_clk", .id = 24, }, + { .n = "macb0_clk", .id = 25, }, + { .n = "isi_clk", .id = 26, }, + { .n = "udphs_clk", .id = 27, }, + { .n = "aestdessha_clk", .id = 28, }, + { .n = "mci1_clk", .id = 29, }, + { .n = "vdec_clk", .id = 30, }, +}; + +static void __init at91sam9g45_pmc_setup(struct device_node *np) +{ + const char *slck_name, *mainxtal_name; + struct pmc_data *at91sam9g45_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; + + at91sam9g45_pmc = pmc_data_allocate(PMC_MAIN + 1, + nck(at91sam9g45_systemck), + nck(at91sam9g45_periphck), 0); + if (!at91sam9g45_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; + + at91sam9g45_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; + + at91sam9g45_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, + &at91rm9200_master_layout, + &mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + at91sam9g45_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; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + 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, + &at91sam9g45_programmable_layout); + if (IS_ERR(hw)) + goto err_free; + } + + for (i = 0; i < ARRAY_SIZE(at91sam9g45_systemck); i++) { + hw = at91_clk_register_system(regmap, at91sam9g45_systemck[i].n, + at91sam9g45_systemck[i].p, + at91sam9g45_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91sam9g45_pmc->shws[at91sam9g45_systemck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(at91sam9g45_periphck); i++) { + hw = at91_clk_register_peripheral(regmap, + at91sam9g45_periphck[i].n, + "masterck", + at91sam9g45_periphck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91sam9g45_pmc->phws[at91sam9g45_periphck[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9g45_pmc); + + return; + +err_free: + pmc_data_free(at91sam9g45_pmc); +} +/* + * The TCB is used as the clocksource so its clock is needed early. This means + * this can't be a platform driver. + */ +CLK_OF_DECLARE_DRIVER(at91sam9g45_pmc, "atmel,at91sam9g45-pmc", + at91sam9g45_pmc_setup); diff --git a/drivers/clk/at91/at91sam9n12.c b/drivers/clk/at91/at91sam9n12.c new file mode 100644 index 000000000000..8bb39d2ba84b --- /dev/null +++ b/drivers/clk/at91/at91sam9n12.c @@ -0,0 +1,238 @@ +// 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 const 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 u8 pllb_out[] = { 0 }; + +static const struct clk_range pllb_outputs[] = { + { .min = 30000000, .max = 100000000 }, +}; + +static const struct clk_pll_characteristics pllb_characteristics = { + .input = { .min = 2000000, .max = 32000000 }, + .num_output = ARRAY_SIZE(pllb_outputs), + .output = pllb_outputs, + .out = pllb_out, +}; + +static const struct { + char *n; + char *p; + u8 id; +} at91sam9n12_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 }, +}; + +static const struct clk_pcr_layout at91sam9n12_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(5, 0), + .div_mask = GENMASK(17, 16), +}; + +struct pck { + char *n; + u8 id; +}; + +static const struct pck at91sam9n12_periphck[] = { + { .n = "pioAB_clk", .id = 2, }, + { .n = "pioCD_clk", .id = 3, }, + { .n = "fuse_clk", .id = 4, }, + { .n = "usart0_clk", .id = 5, }, + { .n = "usart1_clk", .id = 6, }, + { .n = "usart2_clk", .id = 7, }, + { .n = "usart3_clk", .id = 8, }, + { .n = "twi0_clk", .id = 9, }, + { .n = "twi1_clk", .id = 10, }, + { .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 = "tcb_clk", .id = 17, }, + { .n = "pwm_clk", .id = 18, }, + { .n = "adc_clk", .id = 19, }, + { .n = "dma0_clk", .id = 20, }, + { .n = "uhphs_clk", .id = 22, }, + { .n = "udphs_clk", .id = 23, }, + { .n = "lcdc_clk", .id = 25, }, + { .n = "sha_clk", .id = 27, }, + { .n = "ssc0_clk", .id = 28, }, + { .n = "aes_clk", .id = 29, }, + { .n = "trng_clk", .id = 30, }, +}; + +static void __init at91sam9n12_pmc_setup(struct device_node *np) +{ + struct clk_range range = CLK_RANGE(0, 0); + const char *slck_name, *mainxtal_name; + struct pmc_data *at91sam9n12_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; + + at91sam9n12_pmc = pmc_data_allocate(PMC_MAIN + 1, + nck(at91sam9n12_systemck), 31, 0); + if (!at91sam9n12_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; + + at91sam9n12_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_pll(regmap, "pllbck", "mainck", 1, + &at91rm9200_pll_layout, &pllb_characteristics); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "pllbck"; + hw = at91_clk_register_master(regmap, "masterck", 4, parent_names, + &at91sam9x5_master_layout, + &mck_characteristics); + if (IS_ERR(hw)) + goto err_free; + + at91sam9n12_pmc->chws[PMC_MCK] = hw; + + hw = at91sam9n12_clk_register_usb(regmap, "usbck", "pllbck"); + if (IS_ERR(hw)) + goto err_free; + + parent_names[0] = slck_name; + parent_names[1] = "mainck"; + parent_names[2] = "plladivck"; + parent_names[3] = "pllbck"; + 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, + &at91sam9x5_programmable_layout); + if (IS_ERR(hw)) + goto err_free; + } + + for (i = 0; i < ARRAY_SIZE(at91sam9n12_systemck); i++) { + hw = at91_clk_register_system(regmap, at91sam9n12_systemck[i].n, + at91sam9n12_systemck[i].p, + at91sam9n12_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + at91sam9n12_pmc->shws[at91sam9n12_systemck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(at91sam9n12_periphck); i++) { + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &at91sam9n12_pcr_layout, + at91sam9n12_periphck[i].n, + "masterck", + at91sam9n12_periphck[i].id, + &range); + if (IS_ERR(hw)) + goto err_free; + + at91sam9n12_pmc->phws[at91sam9n12_periphck[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, at91sam9n12_pmc); + + return; + +err_free: + pmc_data_free(at91sam9n12_pmc); +} +/* + * The TCB is used as the clocksource so its clock is needed early. This means + * this can't be a platform driver. + */ +CLK_OF_DECLARE_DRIVER(at91sam9n12_pmc, "atmel,at91sam9n12-pmc", + at91sam9n12_pmc_setup); diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index 22aede42a336..31d5c45e30d7 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -25,6 +25,7 @@ struct at91sam9x5_clk_usb { struct clk_hw hw; struct regmap *regmap; u32 usbs_mask; + u8 num_parents; }; #define to_at91sam9x5_clk_usb(hw) \ @@ -75,6 +76,9 @@ static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, tmp_parent_rate = req->rate * div; tmp_parent_rate = clk_hw_round_rate(parent, tmp_parent_rate); + if (!tmp_parent_rate) + continue; + tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div); if (tmp_rate < req->rate) tmp_diff = req->rate - tmp_rate; @@ -107,7 +111,7 @@ static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) { struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); - if (index > 1) + if (index >= usb->num_parents) return -EINVAL; regmap_update_bits(usb->regmap, AT91_PMC_USB, usb->usbs_mask, index); @@ -211,7 +215,8 @@ _at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, usb->hw.init = &init; usb->regmap = regmap; - usb->usbs_mask = SAM9X5_USBS_MASK; + usb->usbs_mask = usbs_mask; + usb->num_parents = num_parents; hw = &usb->hw; ret = clk_hw_register(NULL, &usb->hw); diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index 77398aefeb6d..cc19e8fb83be 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -124,7 +124,6 @@ static const struct { char *n; u8 id; struct clk_range r; - bool pll; } sam9x60_gck[] = { { .n = "flex0_gclk", .id = 5, }, { .n = "flex1_gclk", .id = 6, }, @@ -144,11 +143,9 @@ static const struct { { .n = "sdmmc1_gclk", .id = 26, .r = { .min = 0, .max = 105000000 }, }, { .n = "flex11_gclk", .id = 32, }, { .n = "flex12_gclk", .id = 33, }, - { .n = "i2s_gclk", .id = 34, .r = { .min = 0, .max = 105000000 }, - .pll = true, }, + { .n = "i2s_gclk", .id = 34, .r = { .min = 0, .max = 105000000 }, }, { .n = "pit64b_gclk", .id = 37, }, - { .n = "classd_gclk", .id = 42, .r = { .min = 0, .max = 100000000 }, - .pll = true, }, + { .n = "classd_gclk", .id = 42, .r = { .min = 0, .max = 100000000 }, }, { .n = "tcb1_gclk", .id = 45, }, { .n = "dbgu_gclk", .id = 47, }, }; @@ -237,9 +234,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np) parent_names[0] = "pllack"; parent_names[1] = "upllck"; - parent_names[2] = "mainck"; - parent_names[3] = "mainck"; - hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 4); + parent_names[2] = "main_osc"; + hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 3); if (IS_ERR(hw)) goto err_free; @@ -290,7 +286,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np) sam9x60_gck[i].n, parent_names, 6, sam9x60_gck[i].id, - sam9x60_gck[i].pll, + false, &sam9x60_gck[i].r); if (IS_ERR(hw)) goto err_free; diff --git a/drivers/clk/at91/sama5d3.c b/drivers/clk/at91/sama5d3.c new file mode 100644 index 000000000000..88506f909c08 --- /dev/null +++ b/drivers/clk/at91/sama5d3.c @@ -0,0 +1,240 @@ +// 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 = 166000000 }, + .divisors = { 1, 2, 4, 3 }, +}; + +static u8 plla_out[] = { 0 }; + +static u16 plla_icpll[] = { 0 }; + +static const struct clk_range plla_outputs[] = { + { .min = 400000000, .max = 1000000000 }, +}; + +static const struct clk_pll_characteristics plla_characteristics = { + .input = { .min = 8000000, .max = 50000000 }, + .num_output = ARRAY_SIZE(plla_outputs), + .output = plla_outputs, + .icpll = plla_icpll, + .out = plla_out, +}; + +static const struct clk_pcr_layout sama5d3_pcr_layout = { + .offset = 0x10c, + .cmd = BIT(12), + .pid_mask = GENMASK(6, 0), + .div_mask = GENMASK(17, 16), +}; + +static const struct { + char *n; + char *p; + u8 id; +} sama5d3_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; + struct clk_range r; +} sama5d3_periphck[] = { + { .n = "dbgu_clk", .id = 2, }, + { .n = "hsmc_clk", .id = 5, }, + { .n = "pioA_clk", .id = 6, }, + { .n = "pioB_clk", .id = 7, }, + { .n = "pioC_clk", .id = 8, }, + { .n = "pioD_clk", .id = 9, }, + { .n = "pioE_clk", .id = 10, }, + { .n = "usart0_clk", .id = 12, .r = { .min = 0, .max = 83000000 }, }, + { .n = "usart1_clk", .id = 13, .r = { .min = 0, .max = 83000000 }, }, + { .n = "usart2_clk", .id = 14, .r = { .min = 0, .max = 83000000 }, }, + { .n = "usart3_clk", .id = 15, .r = { .min = 0, .max = 83000000 }, }, + { .n = "uart0_clk", .id = 16, .r = { .min = 0, .max = 83000000 }, }, + { .n = "uart1_clk", .id = 17, .r = { .min = 0, .max = 83000000 }, }, + { .n = "twi0_clk", .id = 18, .r = { .min = 0, .max = 41500000 }, }, + { .n = "twi1_clk", .id = 19, .r = { .min = 0, .max = 41500000 }, }, + { .n = "twi2_clk", .id = 20, .r = { .min = 0, .max = 41500000 }, }, + { .n = "mci0_clk", .id = 21, }, + { .n = "mci1_clk", .id = 22, }, + { .n = "mci2_clk", .id = 23, }, + { .n = "spi0_clk", .id = 24, .r = { .min = 0, .max = 166000000 }, }, + { .n = "spi1_clk", .id = 25, .r = { .min = 0, .max = 166000000 }, }, + { .n = "tcb0_clk", .id = 26, .r = { .min = 0, .max = 166000000 }, }, + { .n = "tcb1_clk", .id = 27, .r = { .min = 0, .max = 166000000 }, }, + { .n = "pwm_clk", .id = 28, }, + { .n = "adc_clk", .id = 29, .r = { .min = 0, .max = 83000000 }, }, + { .n = "dma0_clk", .id = 30, }, + { .n = "dma1_clk", .id = 31, }, + { .n = "uhphs_clk", .id = 32, }, + { .n = "udphs_clk", .id = 33, }, + { .n = "macb0_clk", .id = 34, }, + { .n = "macb1_clk", .id = 35, }, + { .n = "lcdc_clk", .id = 36, }, + { .n = "isi_clk", .id = 37, }, + { .n = "ssc0_clk", .id = 38, .r = { .min = 0, .max = 83000000 }, }, + { .n = "ssc1_clk", .id = 39, .r = { .min = 0, .max = 83000000 }, }, + { .n = "can0_clk", .id = 40, .r = { .min = 0, .max = 83000000 }, }, + { .n = "can1_clk", .id = 41, .r = { .min = 0, .max = 83000000 }, }, + { .n = "sha_clk", .id = 42, }, + { .n = "aes_clk", .id = 43, }, + { .n = "tdes_clk", .id = 44, }, + { .n = "trng_clk", .id = 45, }, + { .n = "fuse_clk", .id = 48, }, + { .n = "mpddr_clk", .id = 49, }, +}; + +static void __init sama5d3_pmc_setup(struct device_node *np) +{ + const char *slck_name, *mainxtal_name; + struct pmc_data *sama5d3_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; + + sama5d3_pmc = pmc_data_allocate(PMC_MAIN + 1, + nck(sama5d3_systemck), + nck(sama5d3_periphck), 0); + if (!sama5d3_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; + + 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; + + sama5d3_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; + + sama5d3_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] = "masterck"; + 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(sama5d3_systemck); i++) { + hw = at91_clk_register_system(regmap, sama5d3_systemck[i].n, + sama5d3_systemck[i].p, + sama5d3_systemck[i].id); + if (IS_ERR(hw)) + goto err_free; + + sama5d3_pmc->shws[sama5d3_systemck[i].id] = hw; + } + + for (i = 0; i < ARRAY_SIZE(sama5d3_periphck); i++) { + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, + &sama5d3_pcr_layout, + sama5d3_periphck[i].n, + "masterck", + sama5d3_periphck[i].id, + &sama5d3_periphck[i].r); + if (IS_ERR(hw)) + goto err_free; + + sama5d3_pmc->phws[sama5d3_periphck[i].id] = hw; + } + + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama5d3_pmc); + + return; + +err_free: + pmc_data_free(sama5d3_pmc); +} +/* + * The TCB is used as the clocksource so its clock is needed early. This means + * this can't be a platform driver. + */ +CLK_OF_DECLARE_DRIVER(sama5d3_pmc, "atmel,sama5d3-pmc", sama5d3_pmc_setup); |