clk: Add Artpec-6 SoC support
Subsystems (3)
Lars Persson
maintainerv5 cover clk: Add Artpec-6 SoC support
Add clock support for the Artpec-6 SoC port. The ARM parts are merged in 4.6-rc1.
Changes since v4:
- Update the maintainer entry with the correct clock directory.
- Implement split clock registration with early clocks through CLK_OF_DECLARE and deferrable clocks through a platform driver.
Changes since v3:
- The binding was corrected to handle two fractional divider clocks as input to the clock controller.
- Updated clk-artpec6.c to handle a distinct fractional divider input for each i2s clock mux.
Changes since v2:
- Moved axis,artpec6-clkctrl.h to the first patch with the DT bindings.
Changes since v1:
- The driver now provides all clocks from the main clock controller block through one DT node.
- Added a header file for the clock indexes.
- Refer to clock-bindings.txt in the bindings document.
Lars Persson (2):
clk: add device tree binding for Artpec-6 clock controller
clk: add artpec-6 clock controller
.../devicetree/bindings/clock/artpec6.txt | 41 ++++ MAINTAINERS | 2 +- drivers/clk/Makefile | 1 + drivers/clk/axis/Makefile | 1 + drivers/clk/axis/clk-artpec6.c | 230 +++++++++++++++++++++ include/dt-bindings/clock/axis,artpec6-clkctrl.h | 38 ++++ 6 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/artpec6.txt create mode 100644 drivers/clk/axis/Makefile create mode 100644 drivers/clk/axis/clk-artpec6.c create mode 100644 include/dt-bindings/clock/axis,artpec6-clkctrl.h
Signature · 1 line
2.1.4
Lars Persson
maintainerPATCH v5 1/2 clk: add device tree binding for Artpec-6 clock controller
Add device tree documentation for the main clock controller in the Artpec-6 SoC.
--- .../devicetree/bindings/clock/artpec6.txt | 41 ++++++++++++++++++++++ include/dt-bindings/clock/axis,artpec6-clkctrl.h | 38 ++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/artpec6.txt create mode 100644 include/dt-bindings/clock/axis,artpec6-clkctrl.h
Documentation/devicetree/bindings/clock/artpec6.txt new file +41 -0
@@ -0,0 +1,41 @@ +* Clock bindings for Axis ARTPEC-6 chip + +The bindings are based on the clock provider binding in +Documentation/devicetree/bindings/clock/clock-bindings.txt + +External clocks: +---------------- + +There are two external inputs to the main clock controller which should be +provided using the common clock bindings. +- "sys_refclk": External 50 Mhz oscillator (required) +- "i2s_refclk": Alternate audio reference clock (optional). + +Main clock controller +--------------------- + +Required properties: +- #clock-cells: Should be <1> + See dt-bindings/clock/axis,artpec6-clkctrl.h for the list of valid identifiers. +- compatible: Should be "axis,artpec6-clkctrl" +- reg: Must contain the base address and length of the system controller +- clocks: Must contain a phandle entry for each clock in clock-names +- clock-names: Must include the external oscillator ("sys_refclk"). Optional + ones are the audio reference clock ("i2s_refclk") and the audio fractional + dividers ("frac_clk0" and "frac_clk1"). + +Examples: + +ext_clk: ext_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <50000000>; +}; + +clkctrl: clkctrl { + #clock-cells = <1>; + compatible = "axis,artpec6-clkctrl"; + reg = <0xf8000000 0x48>; + clocks = <&ext_clk>; + clock-names = "sys_refclk"; +};
include/dt-bindings/clock/axis,artpec6-clkctrl.h new file +38 -0
@@ -0,0 +1,38 @@ +/* +* ARTPEC-6 clock controller indexes +* +* Copyright 2016 Axis Comunications AB. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#ifndef DT_BINDINGS_CLK_ARTPEC6_CLKCTRL_H +#define DT_BINDINGS_CLK_ARTPEC6_CLKCTRL_H + +#define ARTPEC6_CLK_CPU 0 +#define ARTPEC6_CLK_CPU_PERIPH 1 +#define ARTPEC6_CLK_NAND_CLKA 2 +#define ARTPEC6_CLK_NAND_CLKB 3 +#define ARTPEC6_CLK_ETH_ACLK 4 +#define ARTPEC6_CLK_DMA_ACLK 5 +#define ARTPEC6_CLK_PTP_REF 6 +#define ARTPEC6_CLK_SD_PCLK 7 +#define ARTPEC6_CLK_SD_IMCLK 8 +#define ARTPEC6_CLK_I2S_HST 9 +#define ARTPEC6_CLK_I2S0_CLK 10 +#define ARTPEC6_CLK_I2S1_CLK 11 +#define ARTPEC6_CLK_UART_PCLK 12 +#define ARTPEC6_CLK_UART_REFCLK 13 +#define ARTPEC6_CLK_I2C 14 +#define ARTPEC6_CLK_SPI_PCLK 15 +#define ARTPEC6_CLK_SPI_SSPCLK 16 +#define ARTPEC6_CLK_SYS_TIMER 17 +#define ARTPEC6_CLK_FRACDIV_IN 18 +#define ARTPEC6_CLK_DBG_PCLK 19 + +/* This must be the highest clock index plus one. */ +#define ARTPEC6_CLK_NUMCLOCKS 20 + +#endif
Signature · 1 line
2.1.4
Lars Persson
maintainerPATCH v5 2/2 clk: add artpec-6 clock controller
In reply to Lars PerssonAdd a driver for the main clock controller of the Artpec-6 Soc.
--- MAINTAINERS | 2 +- drivers/clk/Makefile | 1 + drivers/clk/axis/Makefile | 1 + drivers/clk/axis/clk-artpec6.c | 230 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/axis/Makefile create mode 100644 drivers/clk/axis/clk-artpec6.c
MAINTAINERS +1 -1
@@ -973,7 +973,7 @@ S: Maintained L: [email protected] F: arch/arm/mach-artpec F: arch/arm/boot/dts/artpec6* -F: drivers/clk/clk-artpec6.c +F: drivers/clk/axis ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT M: Nicolas Ferre <[email protected]>
drivers/clk/Makefile +1 -0
@@ -51,6 +51,7 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o obj-$(CONFIG_COMMON_CLK_AT91) += at91/ +obj-$(CONFIG_ARCH_ARTPEC) += axis/ obj-y += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-$(CONFIG_ARCH_HISI) += hisilicon/
drivers/clk/axis/Makefile new file +1 -0
@@ -0,0 +1 @@ +obj-$(CONFIG_MACH_ARTPEC6) += clk-artpec6.o
drivers/clk/axis/clk-artpec6.c new file +230 -0
230 lines not on this page · raw message
Signature · 1 line
2.1.4
Re: [PATCH v5 2/2] clk: add artpec-6 clock controller
Quoted 14 lines · Lars Persson
drivers/clk/axis/Makefile new file +1
-0@@ -0,0 +1 @@ +obj-$(CONFIG_MACH_ARTPEC6) += clk-artpec6.odrivers/clk/axis/clk-artpec6.c new file +1
-0@@ -0,0 +1,230 @@ +/*
drivers/clk/axis/clk-artpec6.c line 11
Quoted 10 lines
drivers/clk/axis/clk-artpec6.c new file +10
-0+* ARTPEC-6 clock initialization +* +* Copyright 2015-2016 Axis Comunications AB. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include <linux/clk.h>
Is this include used?
drivers/clk/axis/clk-artpec6.c line 13
Quoted 2 lines
drivers/clk/axis/clk-artpec6.c new file +2
-0+#include <linux/clk-provider.h> +#include <linux/clkdev.h>
Is this include used?
Quoted 10 lines
drivers/clk/axis/clk-artpec6.c new file +10
-0+#include <linux/device.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <dt-bindings/clock/axis,artpec6-clkctrl.h> + +#define NUM_I2S_CLOCKS 2 + +struct artpec6_clkctrl_drvdata {
drivers/clk/axis/clk-artpec6.c line 33
Quoted 10 lines
drivers/clk/axis/clk-artpec6.c new file +10
-0+struct clk *clk_table[ARTPEC6_CLK_NUMCLOCKS ]; +void __iomem *syscon_base; +struct clk_onecell_data clk_data; +spinlock_t i2scfg_lock; +}; + + +static struct artpec6_clkctrl_drvdata *clkdata; + +static const char *i2s_clk_names[NUM_I2S_CLOCKS ] = {
const char * const?
Quoted 6 lines
drivers/clk/axis/clk-artpec6.c new file +6
-0+"i2s0" , + "i2s1", +}; + +static const int i2s_clk_indexes[NUM_I2S_CLOCKS ] = { + ARTPEC6_CLK_I2S0_CLK,
drivers/clk/axis/clk-artpec6.c line 49
Quoted 10 lines
drivers/clk/axis/clk-artpec6.c new file +10
-0+ ARTPEC6_CLK_I2S1_CLK, +}; + +static void of_artpec6_clkctrl_setup (struct device_node *np) +{ +int i; +const char *sys_refclk_name; +u32 pll_mode, pll_m, pll_n; + +pr_info ("of_artpec6_clkctrl_setup\n" );
Debug noise?
Quoted 6 lines
drivers/clk/axis/clk-artpec6.c new file +6
-0+ +/* Mandatory parent clock. */ + i =of_property_match_string (np,"clock-names" ,"sys_refclk" ); +if (i <0 ) +return ; +
drivers/clk/axis/clk-artpec6.c line 65
Quoted 10 lines
drivers/clk/axis/clk-artpec6.c new file +10
-0+ sys_refclk_name =of_clk_get_parent_name (np, i); + + clkdata =kzalloc (sizeof (*clkdata),GFP_KERNEL ); +if (!clkdata) +return ; + +for (i =0 ; i <ARTPEC6_CLK_NUMCLOCKS ; ++i) + clkdata->clk_table[i] =ERR_PTR (-EPROBE_DEFER ); + + clkdata->syscon_base =of_iomap (np,0 );
What if that fails?
Quoted 19 lines
drivers/clk/axis/clk-artpec6.c new file +19
-0+ +/* Read PLL1 factors configured by boot strap pins. */ + pll_mode = (readl (clkdata->syscon_base) >>6 ) &3 ; +switch (pll_mode) { +case 0 :/* DDR3-2133 mode */ + pll_m =4 ; + pll_n =85 ; +break ; +case 1 :/* DDR3-1866 mode */ + pll_m =6 ; + pll_n =112 ; +break ; +case 2 :/* DDR3-1600 mode */ + pll_m =4 ; + pll_n =64 ; +break ; +case 3 :/* DDR3-1333 mode */ + pll_m =8 ; + pll_n =106 ;
drivers/clk/axis/clk-artpec6.c line 94
Quoted 10 lines
drivers/clk/axis/clk-artpec6.c new file +10
-0+break ; + } + + clkdata->clk_table[ARTPEC6_CLK_CPU ] = +clk_register_fixed_factor (NULL ,"cpu" , sys_refclk_name,0 , pll_n, + pll_m); + clkdata->clk_table[ARTPEC6_CLK_CPU_PERIPH ] = +clk_register_fixed_factor (NULL ,"cpu_periph" ,"cpu" ,0 ,1 ,2 ); + +/* EPROBE_DEFER on the apb_clock is not handled in amba devices. */
Shouldn't we fix that then?
Quoted 11 lines
drivers/clk/axis/clk-artpec6.c new file +11
-0+ clkdata->clk_table[ARTPEC6_CLK_UART_PCLK ] = +clk_register_fixed_factor (NULL ,"uart_pclk" ,"cpu" ,0 ,1 ,8 ); + clkdata->clk_table[ARTPEC6_CLK_UART_REFCLK ] = +clk_register_fixed_rate (NULL ,"uart_ref" , sys_refclk_name,0 , +50000000 ); + + clkdata->clk_table[ARTPEC6_CLK_SPI_PCLK ] = +clk_register_fixed_factor (NULL ,"spi_pclk" ,"cpu" ,0 ,1 ,8 ); + clkdata->clk_table[ARTPEC6_CLK_SPI_SSPCLK ] = +clk_register_fixed_rate (NULL ,"spi_sspclk" , sys_refclk_name,0 , +50000000 );
drivers/clk/axis/clk-artpec6.c line 115
Quoted 10 lines
drivers/clk/axis/clk-artpec6.c new file +10
-0+ + clkdata->clk_table[ARTPEC6_CLK_DBG_PCLK ] = +clk_register_fixed_factor (NULL ,"dbg_pclk" ,"cpu" ,0 ,1 ,8 ); + + clkdata->clk_data.clks = clkdata->clk_table; + clkdata->clk_data.clk_num =ARTPEC6_CLK_NUMCLOCKS ; + +of_clk_add_provider (np, of_clk_src_onecell_get, &clkdata->clk_data); +} +
Nitpick: Drop newline here.
drivers/clk/axis/clk-artpec6.c line 126
Quoted 11 lines
drivers/clk/axis/clk-artpec6.c new file +11
-0+CLK_OF_DECLARE (artpec6_clkctrl,"axis,artpec6-clkctrl" , + of_artpec6_clkctrl_setup); + +static int artpec6_clkctrl_probe (struct platform_device *pdev) +{ +int propidx; +struct device_node *np = pdev->dev.of_node; +const char *sys_refclk_name; +const char *i2s_refclk_name =NULL ; +const char *frac_clk_name[2 ] = {NULL ,NULL }; +const char *i2s_mux_parents[2 ] = {NULL ,NULL };
Do we need to initialize this to NULL?
drivers/clk/axis/clk-artpec6.c line 128
Quoted 2 lines
drivers/clk/axis/clk-artpec6.c new file +2
-0+u32 muxreg; +u32 i;
int i please.
Quoted 32 lines
drivers/clk/axis/clk-artpec6.c new file +32
-0+ +/* Mandatory parent clock. */ + propidx =of_property_match_string (np,"clock-names" ,"sys_refclk" ); +if (propidx <0 ) +return -EINVAL ; + + sys_refclk_name =of_clk_get_parent_name (np, propidx); + +/* Find clock names of optional parent clocks. */ + propidx =of_property_match_string (np,"clock-names" ,"i2s_refclk" ); +if (propidx >=0 ) + i2s_refclk_name =of_clk_get_parent_name (np, propidx); + + propidx =of_property_match_string (np,"clock-names" ,"frac_clk0" ); +if (propidx >=0 ) + frac_clk_name[0 ] =of_clk_get_parent_name (np, propidx); + propidx =of_property_match_string (np,"clock-names" ,"frac_clk1" ); +if (propidx >=0 ) + frac_clk_name[1 ] =of_clk_get_parent_name (np, propidx); + +spin_lock_init (&clkdata->i2scfg_lock); + + clkdata->clk_table[ARTPEC6_CLK_NAND_CLKA ] = +clk_register_fixed_factor (NULL ,"nand_clka" ,"cpu" ,0 ,1 ,8 ); + clkdata->clk_table[ARTPEC6_CLK_NAND_CLKB ] = +clk_register_fixed_rate (NULL ,"nand_clkb" , sys_refclk_name,0 , +100000000 ); + clkdata->clk_table[ARTPEC6_CLK_ETH_ACLK ] = +clk_register_fixed_factor (NULL ,"eth_aclk" ,"cpu" ,0 ,1 ,4 ); + clkdata->clk_table[ARTPEC6_CLK_DMA_ACLK ] = +clk_register_fixed_factor (NULL ,"dma_aclk" ,"cpu" ,0 ,1 ,4 ); + clkdata->clk_table[ARTPEC6_CLK_PTP_REF] =
drivers/clk/axis/clk-artpec6.c line 170
Quoted 10 lines
drivers/clk/axis/clk-artpec6.c new file +10
-0+clk_register_fixed_rate (NULL ,"ptp_ref" , sys_refclk_name,0 , +100000000 ); + clkdata->clk_table[ARTPEC6_CLK_SD_PCLK ] = +clk_register_fixed_rate (NULL ,"sd_pclk" , sys_refclk_name,0 , +100000000 ); + clkdata->clk_table[ARTPEC6_CLK_SD_IMCLK ] = +clk_register_fixed_rate (NULL ,"sd_imclk" , sys_refclk_name,0 , +100000000 ); + clkdata->clk_table[ARTPEC6_CLK_I2S_HST ] = +clk_register_fixed_factor (NULL ,"i2s_hst" ,"cpu" ,0 ,1 ,8 );
Pass device pointer for all these.
drivers/clk/axis/clk-artpec6.c line 178
Quoted 8 lines
drivers/clk/axis/clk-artpec6.c new file +8
-0+ +for (i =0 ; i <NUM_I2S_CLOCKS ; ++i) { +if (i2s_refclk_name && frac_clk_name[i]) { + i2s_mux_parents[0 ] = frac_clk_name[i]; + i2s_mux_parents[1 ] = i2s_refclk_name; + + clkdata->clk_table[i2s_clk_indexes[i]] = + clk_register_mux(NULL, i2s_clk_names[i],
Please pass the device pointer here.
Quoted 13 lines
drivers/clk/axis/clk-artpec6.c new file +13
-0+ i2s_mux_parents,2 , +CLK_SET_RATE_NO_REPARENT | +CLK_SET_RATE_PARENT , + clkdata->syscon_base +0x14 , i,1 , + 0, &clkdata->i2scfg_lock); + }else if (frac_clk_name[i]) { +/* Lock the mux for internal clock reference. */ + muxreg =readl (clkdata->syscon_base +0x14 ); + muxreg &= ~BIT (i); +writel (muxreg, clkdata->syscon_base +0x14 ); + clkdata->clk_table[i2s_clk_indexes[i]] = + clk_register_fixed_factor(NULL, i2s_clk_names[i], + frac_clk_name[i], 0, 1,
drivers/clk/axis/clk-artpec6.c line 201
Quoted 10 lines
drivers/clk/axis/clk-artpec6.c new file +10
-0+ 1); + }else if (i2s_refclk_name) { +/* Lock the mux for external clock reference. */ + muxreg =readl (clkdata->syscon_base +0x14 ); + muxreg |=BIT (i); +writel (muxreg, clkdata->syscon_base +0x14 ); + clkdata->clk_table[i2s_clk_indexes[i]] = +clk_register_fixed_factor (NULL , i2s_clk_names[i], + i2s_refclk_name,0 ,1 ,1 ); + }
Please assign the register result to some local variable and then assign that local variable to clkdata->clk_table[...] once.
drivers/clk/axis/clk-artpec6.c line 212
Quoted 11 lines
drivers/clk/axis/clk-artpec6.c new file +11
-0+ } + + clkdata->clk_table[ARTPEC6_CLK_I2C ] = +clk_register_fixed_rate (NULL ,"i2c" , sys_refclk_name,0 ,100000000 ); + + clkdata->clk_table[ARTPEC6_CLK_SYS_TIMER ] = +clk_register_fixed_rate (NULL ,"timer" , sys_refclk_name,0 , +100000000 ); + clkdata->clk_table[ARTPEC6_CLK_FRACDIV_IN ] = +clk_register_fixed_rate (NULL ,"fracdiv_in" , sys_refclk_name,0 , +600000000 );
What if any of these fail?
drivers/clk/axis/clk-artpec6.c line 219
Quoted 7 lines
drivers/clk/axis/clk-artpec6.c new file +7
-0+ +return 0 ; +} + +static const struct of_device_id artpec_clkctrl_of_match[] = { + { .compatible ="axis,artpec6-clkctrl" }, + {},
Nitpick: Drop ',' here so that people don't get any wrong ideas.
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
Lars Persson
maintainerRe: [PATCH v5 2/2] clk: add artpec-6 clock controller
Quoted 12 lines · Stephen Boyd
Quoted 11 lines · Lars Persson
drivers/clk/axis/Makefile new file +1
-0@@ -0,0 +1 @@ +obj-$(CONFIG_MACH_ARTPEC6) += clk-artpec6.odrivers/clk/axis/clk-artpec6.c new file +0
-1--- /dev/null
[snip]
Quoted 24 lines
Quoted 24 lines
drivers/clk/axis/clk-artpec6.c new file +23
-0+ +/* Read PLL1 factors configured by boot strap pins. */ + pll_mode = (readl (clkdata->syscon_base) >>6 ) &3 ; +switch (pll_mode) { +case 0 :/* DDR3-2133 mode */ + pll_m =4 ; + pll_n =85 ; +break ; +case 1 :/* DDR3-1866 mode */ + pll_m =6 ; + pll_n =112 ; +break ; +case 2 :/* DDR3-1600 mode */ + pll_m =4 ; + pll_n =64 ; +break ; +case 3 :/* DDR3-1333 mode */ + pll_m =8 ; + pll_n =106 ; +break ; + } + + clkdata->clk_table[ARTPEC6_CLK_CPU] =
Quoted 8 lines
drivers/clk/axis/clk-artpec6.c line 94
Quoted 6 lines
drivers/clk/axis/clk-artpec6.c new file +6
-0+clk_register_fixed_factor (NULL ,"cpu" , sys_refclk_name,0 , pll_n, + pll_m); + clkdata->clk_table[ARTPEC6_CLK_CPU_PERIPH ] = +clk_register_fixed_factor (NULL ,"cpu_periph" ,"cpu" ,0 ,1 ,2 ); + +/* EPROBE_DEFER on the apb_clock is not handled in amba devices. */ Shouldn't we fix that then?
Marek Szyprowski recently tried to fix this, but Russel NAKed the change due to userspace breakage:
https://lkml.org/lkml/2016/2/15/555
Quoted 7 lines
Quoted 6 lines
drivers/clk/axis/clk-artpec6.c new file +5
-0+ clkdata->clk_table[ARTPEC6_CLK_UART_PCLK ] = +clk_register_fixed_factor (NULL ,"uart_pclk" ,"cpu" ,0 ,1 ,8 ); + clkdata->clk_table[ARTPEC6_CLK_UART_REFCLK ] = +clk_register_fixed_rate (NULL ,"uart_ref" , sys_refclk_name,0 , +50000000 );
Re: [PATCH v5 2/2] clk: add artpec-6 clock controller
Quoted 12 lines · Lars Persson
Quoted 5 lines · Stephen Boyd
Review
Quoted 2 lines · Lars Persson
(quoted diff) +2
-0+ + /* EPROBE_DEFER on the apb_clock is not handled in amba devices. */Shouldn't we fix that then?
Marek Szyprowski recently tried to fix this, but Russel NAKed the change due to userspace breakage:
https://lkml.org/lkml/2016/2/15/555
Thanks for the pointer. It looks like the discussion stalled though... I guess I'll merge v6 assuming it's all good otherwise and make a todo to circle back once the amba bus is fixed.
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project