diff options
31 files changed, 1814 insertions, 181 deletions
diff --git a/Documentation/devicetree/bindings/clock/arm,syscon-icst.yaml b/Documentation/devicetree/bindings/clock/arm,syscon-icst.yaml new file mode 100644 index 000000000000..de9a465096db --- /dev/null +++ b/Documentation/devicetree/bindings/clock/arm,syscon-icst.yaml @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/arm,syscon-icst.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM System Controller ICST Clocks + +maintainers: + - Linus Walleij <linusw@kernel.org> + +description: | + The ICS525 and ICS307 oscillators are produced by Integrated + Devices Technology (IDT). ARM integrated these oscillators deeply into their + reference designs by adding special control registers that manage such + oscillators to their system controllers. + + The various ARM system controllers contain logic to serialize and initialize + an ICST clock request after a write to the 32 bit register at an offset + into the system controller. Furthermore, to even be able to alter one of + these frequencies, the system controller must first be unlocked by + writing a special token to another offset in the system controller. + + Some ARM hardware contain special versions of the serial interface that only + connects the low 8 bits of the VDW (missing one bit), hard-wires RDW to + different values and sometimes also hard-wires the output divider. They + therefore have special compatible strings as per this table (the OD value is + the value on the pins, not the resulting output divider). + + In the core modules and logic tiles, the ICST is a configurable clock fed + from a 24 MHz clock on the motherboard (usually the main crystal) used for + generating e.g. video clocks. It is located on the core module and there is + only one of these. This clock node must be a subnode of the core module. + + Hardware variant RDW OD VDW + + Integrator/AP 22 1 Bit 8 0, rest variable + integratorap-cm + + Integrator/AP 46 3 Bit 8 0, rest variable + integratorap-sys + + Integrator/AP 22 or 1 17 or (33 or 25 MHz) + integratorap-pci 14 1 14 + + Integrator/CP 22 variable Bit 8 0, rest variable + integratorcp-cm-core + + Integrator/CP 22 variable Bit 8 0, rest variable + integratorcp-cm-mem + + The ICST oscillator must be provided inside a system controller node. + +properties: + "#clock-cells": + const: 0 + + compatible: + enum: + - arm,syscon-icst525 + - arm,syscon-icst307 + - arm,syscon-icst525-integratorap-cm + - arm,syscon-icst525-integratorap-sys + - arm,syscon-icst525-integratorap-pci + - arm,syscon-icst525-integratorcp-cm-core + - arm,syscon-icst525-integratorcp-cm-mem + - arm,integrator-cm-auxosc + - arm,versatile-cm-auxosc + - arm,impd-vco1 + - arm,impd-vco2 + + clocks: + description: Parent clock for the ICST VCO + maxItems: 1 + + clock-output-names: + maxItems: 1 + + lock-offset: + $ref: '/schemas/types.yaml#/definitions/uint32' + description: Offset to the unlocking register for the oscillator + + vco-offset: + $ref: '/schemas/types.yaml#/definitions/uint32' + description: Offset to the VCO register for the oscillator + +required: + - "#clock-cells" + - compatible + - clocks + +examples: + - | + vco1: clock@00 { + compatible = "arm,impd1-vco1"; + #clock-cells = <0>; + lock-offset = <0x08>; + vco-offset = <0x00>; + clocks = <&sysclk>; + clock-output-names = "IM-PD1-VCO1"; + }; + +... diff --git a/Documentation/devicetree/bindings/clock/arm-integrator.txt b/Documentation/devicetree/bindings/clock/arm-integrator.txt deleted file mode 100644 index 11f5f95f571b..000000000000 --- a/Documentation/devicetree/bindings/clock/arm-integrator.txt +++ /dev/null @@ -1,34 +0,0 @@ -Clock bindings for ARM Integrator and Versatile Core Module clocks - -Auxiliary Oscillator Clock - -This is a configurable clock fed from a 24 MHz chrystal, -used for generating e.g. video clocks. It is located on the -core module and there is only one of these. - -This clock node *must* be a subnode of the core module, since -it obtains the base address for it's address range from its -parent node. - - -Required properties: -- compatible: must be "arm,integrator-cm-auxosc" or "arm,versatile-cm-auxosc" -- #clock-cells: must be <0> - -Optional properties: -- clocks: parent clock(s) - -Example: - -core-module@10000000 { - xtal24mhz: xtal24mhz@24M { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <24000000>; - }; - auxosc: cm_aux_osc@25M { - #clock-cells = <0>; - compatible = "arm,integrator-cm-auxosc"; - clocks = <&xtal24mhz>; - }; -}; diff --git a/Documentation/devicetree/bindings/clock/arm-syscon-icst.txt b/Documentation/devicetree/bindings/clock/arm-syscon-icst.txt deleted file mode 100644 index 4cd81742038f..000000000000 --- a/Documentation/devicetree/bindings/clock/arm-syscon-icst.txt +++ /dev/null @@ -1,70 +0,0 @@ -ARM System Controller ICST clocks - -The ICS525 and ICS307 oscillators are produced by Integrated Devices -Technology (IDT). ARM integrated these oscillators deeply into their -reference designs by adding special control registers that manage such -oscillators to their system controllers. - -The various ARM system controllers contain logic to serialize and initialize -an ICST clock request after a write to the 32 bit register at an offset -into the system controller. Furthermore, to even be able to alter one of -these frequencies, the system controller must first be unlocked by -writing a special token to another offset in the system controller. - -Some ARM hardware contain special versions of the serial interface that only -connects the low 8 bits of the VDW (missing one bit), hardwires RDW to -different values and sometimes also hardwire the output divider. They -therefore have special compatible strings as per this table (the OD value is -the value on the pins, not the resulting output divider): - -Hardware variant: RDW OD VDW - -Integrator/AP 22 1 Bit 8 0, rest variable -integratorap-cm - -Integrator/AP 46 3 Bit 8 0, rest variable -integratorap-sys - -Integrator/AP 22 or 1 17 or (33 or 25 MHz) -integratorap-pci 14 1 14 - -Integrator/CP 22 variable Bit 8 0, rest variable -integratorcp-cm-core - -Integrator/CP 22 variable Bit 8 0, rest variable -integratorcp-cm-mem - -The ICST oscillator must be provided inside a system controller node. - -Required properties: -- compatible: must be one of - "arm,syscon-icst525" - "arm,syscon-icst307" - "arm,syscon-icst525-integratorap-cm" - "arm,syscon-icst525-integratorap-sys" - "arm,syscon-icst525-integratorap-pci" - "arm,syscon-icst525-integratorcp-cm-core" - "arm,syscon-icst525-integratorcp-cm-mem" -- lock-offset: the offset address into the system controller where the - unlocking register is located -- vco-offset: the offset address into the system controller where the - ICST control register is located (even 32 bit address) -- #clock-cells: must be <0> -- clocks: parent clock, since the ICST needs a parent clock to derive its - frequency from, this attribute is compulsory. - -Example: - -syscon: syscon@10000000 { - compatible = "syscon"; - reg = <0x10000000 0x1000>; - - oscclk0: osc0@c { - compatible = "arm,syscon-icst307"; - #clock-cells = <0>; - lock-offset = <0x20>; - vco-offset = <0x0c>; - clocks = <&xtal24mhz>; - }; - (...) -}; diff --git a/Documentation/devicetree/bindings/clock/marvell,mmp2-clock.yaml b/Documentation/devicetree/bindings/clock/marvell,mmp2-clock.yaml new file mode 100644 index 000000000000..e2b6ac96bbcb --- /dev/null +++ b/Documentation/devicetree/bindings/clock/marvell,mmp2-clock.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/marvell,mmp2-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell MMP2 and MMP3 Clock Controller + +maintainers: + - Lubomir Rintel <lkundrak@v3.sk> + +description: | + The clock subsystem on MMP2 or MMP3 generates and supplies clock to various + controllers within the SoC. + + Each clock is assigned an identifier and client nodes use this identifier + to specify the clock which they consume. + + All these identifiers could be found in <dt-bindings/clock/marvell,mmp2.h>. + +properties: + compatible: + enum: + - marvell,mmp2-clock # controller compatible with MMP2 SoC + - marvell,mmp3-clock # controller compatible with MMP3 SoC + + reg: + items: + - description: MPMU register region + - description: APMU register region + - description: APBC register region + + reg-names: + items: + - const: mpmu + - const: apmu + - const: apbc + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + +required: + - compatible + - reg + - reg-names + - '#clock-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + clock-controller@d4050000 { + compatible = "marvell,mmp2-clock"; + reg = <0xd4050000 0x1000>, + <0xd4282800 0x400>, + <0xd4015000 0x1000>; + reg-names = "mpmu", "apmu", "apbc"; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/marvell,mmp2.txt b/Documentation/devicetree/bindings/clock/marvell,mmp2.txt deleted file mode 100644 index 23b52dc02266..000000000000 --- a/Documentation/devicetree/bindings/clock/marvell,mmp2.txt +++ /dev/null @@ -1,21 +0,0 @@ -* Marvell MMP2 Clock Controller - -The MMP2 clock subsystem generates and supplies clock to various -controllers within the MMP2 SoC. - -Required Properties: - -- compatible: should be one of the following. - - "marvell,mmp2-clock" - controller compatible with MMP2 SoC. - -- reg: physical base address of the clock subsystem and length of memory mapped - region. There are 3 places in SOC has clock control logic: - "mpmu", "apmu", "apbc". So three reg spaces need to be defined. - -- #clock-cells: should be 1. -- #reset-cells: should be 1. - -Each clock is assigned an identifier and client nodes use this identifier -to specify the clock which they consume. - -All these identifiers could be found in <dt-bindings/clock/marvell,mmp2.h>. diff --git a/Documentation/devicetree/bindings/clock/ti,am654-ehrpwm-tbclk.yaml b/Documentation/devicetree/bindings/clock/ti,am654-ehrpwm-tbclk.yaml new file mode 100644 index 000000000000..869b18ac88d7 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti,am654-ehrpwm-tbclk.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/ti,am654-ehrpwm-tbclk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI EHRPWM Time Base Clock + +maintainers: + - Vignesh Raghavendra <vigneshr@ti.com> + +properties: + compatible: + items: + - const: ti,am654-ehrpwm-tbclk + - const: syscon + + "#clock-cells": + const: 1 + + reg: + maxItems: 1 + +required: + - compatible + - "#clock-cells" + - reg + +examples: + - | + ehrpwm_tbclk: syscon@4140 { + compatible = "ti,am654-ehrpwm-tbclk", "syscon"; + reg = <0x4140 0x18>; + #clock-cells = <1>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 38fe2f3f7b6f..04499e55218b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1280,7 +1280,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/arm/arm-boards F: Documentation/devicetree/bindings/auxdisplay/arm-charlcd.txt -F: Documentation/devicetree/bindings/clock/arm-integrator.txt +F: Documentation/devicetree/bindings/clock/arm,syscon-icst.yaml F: Documentation/devicetree/bindings/i2c/i2c-versatile.txt F: Documentation/devicetree/bindings/interrupt-controller/arm,versatile-fpga-irq.txt F: Documentation/devicetree/bindings/mtd/arm-versatile.txt 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, +}; + < |
