Enable wifi on pandaboard
Subsystems (6)
cover Enable wifi on pandaboard
On the pandaboard the wifi isn't available because on the TWL6030 chip the clock CLK32KG never gets enabled. Adding a clock driver for the TWL6030 which performs the required steps. Moved some register defines from regulator code to twl.h.
Stefan Assmann (2):
mfd: twl-core: move TWL6030 defines to twl.h
clk: initial clock driver for TWL6030
.../devicetree/bindings/clock/ti/twl6030.txt | 4 + drivers/clk/Kconfig | 7 + drivers/clk/ti/Makefile | 1 + drivers/clk/ti/clk-6030.c | 141 +++++++++++++++++++++ drivers/mfd/twl-core.c | 3 + drivers/regulator/twl-regulator.c | 11 -- include/linux/i2c/twl.h | 20 +++ 7 files changed, 176 insertions(+), 11 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/ti/twl6030.txt create mode 100644 drivers/clk/ti/clk-6030.c
Signature · 1 line
1.9.3
PATCH 1/2 mfd: twl-core: move TWL6030 defines to twl.h
These defines should be available to all drivers. Also added register offset for CLK32KG_CFG_STATE and GRP defines.
--- drivers/regulator/twl-regulator.c | 11 ----------- include/linux/i2c/twl.h | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 11 deletions(-)
drivers/regulator/twl-regulator.c +0 -11
@@ -94,17 +94,6 @@ struct twlreg_info {#define VREG_BC_PROC 3#define VREG_BC_CLK_RST 4 -/* TWL6030 LDO register values for CFG_STATE */ -#define TWL6030_CFG_STATE_OFF 0x00 -#define TWL6030_CFG_STATE_ON 0x01 -#define TWL6030_CFG_STATE_OFF2 0x02 -#define TWL6030_CFG_STATE_SLEEP 0x03 -#define TWL6030_CFG_STATE_GRP_SHIFT 5 -#define TWL6030_CFG_STATE_APP_SHIFT 2 -#define TWL6030_CFG_STATE_APP_MASK (0x03 << TWL6030_CFG_STATE_APP_SHIFT) -#define TWL6030_CFG_STATE_APP (v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\ - TWL6030_CFG_STATE_APP_SHIFT) -/* Flags for SMPS Voltage reading */ #define SMPS_OFFSET_EN BIT(0)#define SMPS_EXTENDED_EN BIT(1)
include/linux/i2c/twl.h +20 -0
@@ -127,6 +127,20 @@ enum twl6030_module_ids {#define REG_INT_MSK_STS_B 0x07#define REG_INT_MSK_STS_C 0x08 +/* TWL6030 register values for CFG_STATE */ +#define TWL6030_GRP_APP (1 << 0) +#define TWL6030_GRP_CON (1 << 1) +#define TWL6030_GRP_MOD (1 << 2) +#define TWL6030_CFG_STATE_OFF 0x00 +#define TWL6030_CFG_STATE_ON 0x01 +#define TWL6030_CFG_STATE_OFF2 0x02 +#define TWL6030_CFG_STATE_SLEEP 0x03 +#define TWL6030_CFG_STATE_GRP_SHIFT 5 +#define TWL6030_CFG_STATE_APP_SHIFT 2 +#define TWL6030_CFG_STATE_APP_MASK (0x03 << TWL6030_CFG_STATE_APP_SHIFT) +#define TWL6030_CFG_STATE_APP (v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\ + TWL6030_CFG_STATE_APP_SHIFT) +/* MASK INT REG GROUP A */ #define TWL6030_PWR_INT_MASK 0x07#define TWL6030_RTC_INT_MASK 0x18
@@ -470,6 +484,12 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)#define TWL4030_PM_MASTER_GLOBAL_TST 0xb6 +/* +* PM Receiver module register offsets (use TWL_MODULE_PM_RECEIVER) +*/ + +#define TWL6030_PM_RECEIVER_CLK32KG_CFG_STATE 0x8e +/*----------------------------------------------------------------------*/ /* Power bus message definitions */
Signature · 1 line
1.9.3
PATCH 1/2 mfd: twl-core: move TWL6030 defines to twl.h
Quoted 8 lines · Stefan Assmann
These defines should be available to all drivers. Also added register offset for
CLK32KG_CFG_STATEand GRP defines.Signed-off-by Stefan Assmann <[email protected]>--- drivers/regulator/twl-regulator.c | 11 ----------- include/linux/i2c/twl.h | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 11 deletions(-)
This doesn't have anything to do with MFD?
Signature · 4 lines
Lee Jones Linaro STMicroelectronics Landing Team Lead Linaro.org ? Open source software for ARM SoCs Follow Linaro: Facebook | Twitter | Blog
PATCH 1/2 mfd: twl-core: move TWL6030 defines to twl.h
Quoted 5 lines · Lee Jones
Quoted 3 lines · Stefan Assmann
These defines should be available to all drivers. Also added register offset for
CLK32KG_CFG_STATEand GRP defines.
Quoted 8 lines
Quoted 5 lines
Signed-off-by Stefan Assmann <[email protected]>--- drivers/regulator/twl-regulator.c | 11 ----------- include/linux/i2c/twl.h | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 11 deletions(-)This doesn't have anything to do with MFD?
I added mfd because many other commits in include/linux/i2c/twl.h reference it. We can drop it if you like.
Stefan
PATCH 2/2 clk: initial clock driver for TWL6030
In reply to Stefan AssmannAdding a clock driver for the TI TWL6030. The driver prepares the CLK32KG clock, which is required for the wireless LAN.
--- .../devicetree/bindings/clock/ti/twl6030.txt | 4 + drivers/clk/Kconfig | 7 + drivers/clk/ti/Makefile | 1 + drivers/clk/ti/clk-6030.c | 141 +++++++++++++++++++++ drivers/mfd/twl-core.c | 3 + 5 files changed, 156 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/ti/twl6030.txt create mode 100644 drivers/clk/ti/clk-6030.c
Documentation/devicetree/bindings/clock/ti/twl6030.txt new file +4 -0
@@ -0,0 +1,4 @@ +Binding for TI TWL6030. + +Required properties: +- compatible: "ti,twl6030-clk32kg"
drivers/clk/Kconfig +7 -0
@@ -65,6 +65,13 @@ config COMMON_CLK_S2MPS11 clock. These multi-function devices have two (S2MPS14) or three (S2MPS11, S5M8767) fixed-rate oscillators, clocked at 32KHz each. +config CLK_TWL6030 + tristate "Clock driver for twl6030" + depends on TWL4030_CORE + ---help--- + Enable the TWL6030 clock CLK32KG which is disabled by default. + Needed on the Pandaboard for the wireless LAN. + config CLK_TWL6040 tristate "External McPDM functional clock from twl6040" depends on TWL6040_CORE
drivers/clk/ti/Makefile +1 -0
@@ -10,4 +10,5 @@ obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \ clk-dra7-atl.o obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o +obj-$(CONFIG_CLK_TWL6030) += $(clk-common) clk-6030.o endif
drivers/clk/ti/clk-6030.c new file +141 -0
141 lines not on this page · raw message
drivers/mfd/twl-core.c +3 -0
@@ -34,6 +34,7 @@#include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/err.h> #include <linux/device.h> #include <linux/of.h>
@@ -1012,6 +1013,8 @@ static void clocks_init(struct device *dev,u32 rate;u8 ctrl =HFCLK_FREQ_26_MHZ ; +of_clk_init (NULL ); + osc =clk_get (dev,"fck" );if (IS_ERR (osc)) { printk(KERN_WARNING "Skipping twl internal clock init and "
Signature · 1 line
1.9.3
PATCH 2/2 clk: initial clock driver for TWL6030
Hi Stefan,
Glad you got it working. :)
Small nit below:
Am 30.07.2014 16:02, schrieb Stefan Assmann:
Quoted 6 lines
drivers/clk/ti/clk-6030.c new file +0
-0
drivers/clk/ti/clk-6030.c line 8
Quoted 8 lines
drivers/clk/ti/clk-6030.c new file +8
-0@@ -0,0 +1,141 @@ +/* +* drivers/clk/ti/clk-6030.c +* +* Copyright (C) 2014 Stefan Assmann <[email protected]> +* +* 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.
Here you say version 2 ...
Quoted 3 lines
drivers/clk/ti/clk-6030.c new file +3
-0+* +* Clock driver for ti twl6030. +*/
[...]
drivers/clk/ti/clk-6030.c line 141
Quoted 3 lines
drivers/clk/ti/clk-6030.c new file +3
-0+MODULE_AUTHOR ("Stefan Assmann <[email protected]>" ); +MODULE_DESCRIPTION ("clock driver for TI SoC based boards with twl6030" ); +MODULE_LICENSE ("GPL" );
... but down here it's "GPL". Either use "GPL v2" here, or IIUC use the "or (at your option) any later version" license above if you can.
Cheers,
Andreas
Signature · 2 lines
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany GF: Jeff Hawn, Jennifer Guild, Felix Imend?rffer; HRB 16746 AG N?rnberg
PATCH 2/2 clk: initial clock driver for TWL6030
Quoted 27 lines · Andreas F?rber
Hi Stefan,
Glad you got it working. :)
Small nit below:
Am 30.07.2014 16:02, schrieb Stefan Assmann:
Quoted 6 lines
drivers/clk/ti/clk-6030.c new file +0
-0drivers/clk/ti/clk-6030.c line 8
Quoted 8 lines
drivers/clk/ti/clk-6030.c new file +8
-0@@ -0,0 +1,141 @@ +/* +* drivers/clk/ti/clk-6030.c +* +* Copyright (C) 2014 Stefan Assmann <[email protected]> +* +* 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. Here you say version 2 ...
drivers/clk/ti/clk-6030.c line 11
Quoted 3 lines
drivers/clk/ti/clk-6030.c new file +3
-0+* +* Clock driver for ti twl6030. +*/
Quoted 7 lines
[...]
drivers/clk/ti/clk-6030.c line 141
Quoted 3 lines
drivers/clk/ti/clk-6030.c new file +3
-0+MODULE_AUTHOR ("Stefan Assmann <[email protected]>" ); +MODULE_DESCRIPTION ("clock driver for TI SoC based boards with twl6030" ); +MODULE_LICENSE ("GPL" );... but down here it's "GPL". Either use "GPL v2" here, or IIUC use the "or (at your option) any later version" license above if you can.
Thanks for the hint. I'll fix it in the next version. :)
Stefan
Mark Brown
maintainerPATCH 2/2 clk: initial clock driver for TWL6030
In reply to Stefan Assmanndrivers/clk/ti/clk-6030.c line 58
Quoted 6 lines · Stefan Assmann
drivers/clk/ti/clk-6030.c new file +6
-0+static int twl6030_clk32kg_is_prepared (struct clk_hw *hw) +{ +struct twl6030_desc *desc =to_twl6030_desc (hw); + +return desc->enabled; +}
Why not just check the register map - can't the register be cached? If that's not possible a comment would be good.
drivers/clk/ti/clk-6030.c line 114
Quoted 10 lines
drivers/clk/ti/clk-6030.c new file +10
-0+static int of_twl6030_clk32kg_probe (struct platform_device *pdev) +{ +struct device_node *node = pdev->dev.of_node; +struct clk *clk; +int ret =0 ; + +if (!node) +return -ENODEV ; + + clk =clk_get (&pdev->dev,"clk32kg" );
devm_clk_get()?
drivers/clk/ti/clk-6030.c line 116
Quoted 2 lines
drivers/clk/ti/clk-6030.c new file +2
-0+if (IS_ERR (clk)) + ret = -EPROBE_DEFER ;
Shouldn't the provided return code be being used?
drivers/clk/ti/clk-6030.c line 118
Quoted 2 lines
drivers/clk/ti/clk-6030.c new file +2
-0+else +clk_prepare (clk);
Why is the clock driver defaulting to enabling the clock, and if it needs to shouldn't it be doing a prepere_enable() even if the enable happens not to do anything to the hardware? Otherwise child clocks might get confused.
The return value is also not being checked.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140730/ed6a6771/attachment.sig>
PATCH 2/2 clk: initial clock driver for TWL6030
Quoted 11 lines · Mark Brown
Review
Quoted 6 lines · Stefan Assmann
(quoted diff) +6
-0+static int twl6030_clk32kg_is_prepared(struct clk_hw *hw) +{ + struct twl6030_desc *desc = to_twl6030_desc(hw); + + return desc->enabled; +}Why not just check the register map - can't the register be cached? If that's not possible a comment would be good.
I just took atl_clk_is_enabled() as template. If you say it's better to read the value, that can be arranged.
Quoted 13 lines
Review
Quoted 11 lines
(quoted diff) +10
-0+static int of_twl6030_clk32kg_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct clk *clk; + int ret = 0; + + if (!node) + return -ENODEV; + + clk = clk_get(&pdev->dev, "clk32kg");
devm_clk_get()?
Changed.
Quoted 5 lines
Review
Quoted 3 lines
(quoted diff) +2
-0+ if (IS_ERR(clk)) + ret = -EPROBE_DEFER;Shouldn't the provided return code be being used?
Changed.
Quoted 8 lines
Review
Quoted 3 lines
(quoted diff) +2
-0+ else + clk_prepare(clk);Why is the clock driver defaulting to enabling the clock, and if it needs to shouldn't it be doing a
prepere_enable()even if the enable happens not to do anything to the hardware? Otherwise child clocks might get confused.
Mike advised me to convert the functions from enable/disable to prepare/unprepare because i2c transactions may sleep. That's what I did. The code no longer enables the clock and just prepares it. So IIUC the call to clk_prepare() should be fine.
Quoted 3 lines
The return value is also not being checked.
Changed.
Thanks for your comments Mark, here's a new version of the patch.
Stefan
Quoted 1 line
From
2c52040f33af9dbb41e3e3f355ae154843b277c6Mon Sep 17 00:00:00 2001
From: Stefan Assmann <[email protected]>
Date: Fri, 25 Jul 2014 09:42:27 +0200
Subject: [PATCH] clk: initial clock driver for TWL6030
Adding a clock driver for the TI TWL6030. The driver prepares the CLK32KG clock, which is required for the wireless LAN.
v2:
- use MODULE_LICENSE("GPL v2")
- use devm_clk_get() instead of clk_get()
- propagate return value of clk_prepare()
- read prepared state instead of using enabled variable
--- .../devicetree/bindings/clock/ti/twl6030.txt | 4 + drivers/clk/Kconfig | 7 ++ drivers/clk/ti/Makefile | 1 + drivers/clk/ti/clk-6030.c | 133 +++++++++++++++++++++ drivers/mfd/twl-core.c | 3 + 5 files changed, 148 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/ti/twl6030.txt create mode 100644 drivers/clk/ti/clk-6030.c
Documentation/devicetree/bindings/clock/ti/twl6030.txt new file +4 -0
@@ -0,0 +1,4 @@ +Binding for TI TWL6030. + +Required properties: +- compatible: "ti,twl6030-clk32kg"
drivers/clk/Kconfig +7 -0
@@ -65,6 +65,13 @@ config COMMON_CLK_S2MPS11 clock. These multi-function devices have two (S2MPS14) or three (S2MPS11, S5M8767) fixed-rate oscillators, clocked at 32KHz each. +config CLK_TWL6030 + tristate "Clock driver for twl6030" + depends on TWL4030_CORE + ---help--- + Enable the TWL6030 clock CLK32KG which is disabled by default. + Needed on the Pandaboard for the wireless LAN. + config CLK_TWL6040 tristate "External McPDM functional clock from twl6040" depends on TWL6040_CORE
drivers/clk/ti/Makefile +1 -0
@@ -10,4 +10,5 @@ obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \ clk-dra7-atl.o obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o +obj-$(CONFIG_CLK_TWL6030) += $(clk-common) clk-6030.o endif
drivers/clk/ti/clk-6030.c new file +133 -0
133 lines not on this page · raw message
drivers/mfd/twl-core.c +3 -0
@@ -34,6 +34,7 @@#include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/err.h> #include <linux/device.h> #include <linux/of.h>
@@ -1012,6 +1013,8 @@ static void clocks_init(struct device *dev,u32 rate;u8 ctrl =HFCLK_FREQ_26_MHZ ; +of_clk_init (NULL ); + osc =clk_get (dev,"fck" );if (IS_ERR (osc)) { printk(KERN_WARNING "Skipping twl internal clock init and "
Signature · 1 line
1.9.3
Mark Brown
maintainerPATCH 2/2 clk: initial clock driver for TWL6030
Quoted 13 lines · Stefan Assmann
Quoted 11 lines · Mark Brown
drivers/clk/ti/clk-6030.c line 53
Quoted 6 lines · Stefan Assmann
drivers/clk/ti/clk-6030.c new file +6
-0+static int twl6030_clk32kg_is_prepared (struct clk_hw *hw) +{ +struct twl6030_desc *desc =to_twl6030_desc (hw); + +return desc->enabled; +}Why not just check the register map - can't the register be cached? If that's not possible a comment would be good.
Quoted 2 lines
I just took
atl_clk_is_enabled()as template. If you say it's better to read the value, that can be arranged.
It might be worth doing this if you have to go to hardware to check the status, if you can read a cache then just using the register is less error prone.
Quoted 8 lines
Quoted 7 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ else + clk_prepare(clk);Why is the clock driver defaulting to enabling the clock, and if it needs to shouldn't it be doing a
prepere_enable()even if the enable happens not to do anything to the hardware? Otherwise child clocks might get confused.
Quoted 4 lines
Mike advised me to convert the functions from enable/disable to prepare/unprepare because i2c transactions may sleep. That's what I did. The code no longer enables the clock and just prepares it. So IIUC the call to
clk_prepare()should be fine.
That's not going to help consumers of the clock, you do need to move the operations to prepare() but users shouldn't need to know what happens in prepare() and what happens in enable().
You've also not addressed the comment about defaulting to enabling the
clock in the first place.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140731/d5677193/attachment-0001.sig>
PATCH 2/2 clk: initial clock driver for TWL6030
Quoted 14 lines · Mark Brown
Quoted 12 lines · Stefan Assmann
Quoted 11 lines · Mark Brown
drivers/clk/ti/clk-6030.c line 53
Quoted 6 lines · Stefan Assmann
drivers/clk/ti/clk-6030.c new file +6
-0+static int twl6030_clk32kg_is_prepared (struct clk_hw *hw) +{ +struct twl6030_desc *desc =to_twl6030_desc (hw); + +return desc->enabled; +}Why not just check the register map - can't the register be cached? If that's not possible a comment would be good.
Quoted 6 lines
Quoted 2 lines
I just took
atl_clk_is_enabled()as template. If you say it's better to read the value, that can be arranged.It might be worth doing this if you have to go to hardware to check the status, if you can read a cache then just using the register is less error prone.
Ok.
Quoted 14 lines
Quoted 9 lines
Quoted 8 lines
Review
Quoted 3 lines
(quoted diff) +2
-0+ else + clk_prepare(clk);Why is the clock driver defaulting to enabling the clock, and if it needs to shouldn't it be doing a
prepere_enable()even if the enable happens not to do anything to the hardware? Otherwise child clocks might get confused.Quoted 4 lines
Mike advised me to convert the functions from enable/disable to prepare/unprepare because i2c transactions may sleep. That's what I did. The code no longer enables the clock and just prepares it. So IIUC the call to
clk_prepare()should be fine.
Quoted 6 lines
That's not going to help consumers of the clock, you do need to move the operations to
prepare()but users shouldn't need to know what happens inprepare()and what happens inenable().You've also not addressed the comment about defaulting to enabling the clock in the first place.
Maybe I misinterpreted your previous comment, sorry. So if I got it right this time you're saying that the prepare/enable, disable/unprepare should be seen as a single step. If that's the case then using prepare_enable() should be used indeed.
Tero suggested to look into making this a generic i2c clock driver. I'll look into that and report back.
Stefan
PATCH 2/2 clk: initial clock driver for TWL6030
Quoting Stefan Assmann (2014-07-31 05:04:29)
Quoted 42 lines · Mark Brown
Quoted 14 lines · Stefan Assmann
Quoted 12 lines · Mark Brown
Quoted 11 lines · Stefan Assmann
drivers/clk/ti/clk-6030.c line 53
Quoted 7 lines
drivers/clk/ti/clk-6030.c new file +6
-0+static int twl6030_clk32kg_is_prepared (struct clk_hw *hw) +{ +struct twl6030_desc *desc =to_twl6030_desc (hw); + +return desc->enabled; +}Why not just check the register map - can't the register be cached? If that's not possible a comment would be good.
Quoted 6 lines
Quoted 2 lines
I just took
atl_clk_is_enabled()as template. If you say it's better to read the value, that can be arranged.It might be worth doing this if you have to go to hardware to check the status, if you can read a cache then just using the register is less error prone.
Ok.
Quoted 18 lines
Quoted 9 lines
Quoted 8 lines
Review
Quoted 3 lines
(quoted diff) +2
-0+ else + clk_prepare(clk);Why is the clock driver defaulting to enabling the clock, and if it needs to shouldn't it be doing a
prepere_enable()even if the enable happens not to do anything to the hardware? Otherwise child clocks might get confused.Quoted 4 lines
Mike advised me to convert the functions from enable/disable to prepare/unprepare because i2c transactions may sleep. That's what I did. The code no longer enables the clock and just prepares it. So IIUC the call to
clk_prepare()should be fine.That's not going to help consumers of the clock, you do need to move the operations to
prepare()but users shouldn't need to know what happens inprepare()and what happens inenable().
Quoted 7 lines
Quoted 2 lines
You've also not addressed the comment about defaulting to enabling the clock in the first place.
Maybe I misinterpreted your previous comment, sorry. So if I got it right this time you're saying that the prepare/enable, disable/unprepare should be seen as a single step. If that's the case then using
prepare_enable()should be used indeed.
It's not so much that they are single step. The point is that the way we ungate a clock signal using the Linux clk.h api is by calling clk_enable().
If you read the code for clk_enable you'll see that it depends on the clock already having been prepared via clk_prepare(). The fact that your particular implementation of this clock driver actually ungates the physical signal via clk_prepare is irrelevant from the api's perspective. clk_enable is how we turn gateable clocks on, even if the hardware really gets affected by the prior call to clk_prepare.
It would be a real mess if drivers knew the details of their underlying clock hardware and only called clk_prepare and never clk_enable to gate/ungate their clocks.
Regards,
Mike
Quoted 5 lines
Tero suggested to look into making this a generic i2c clock driver. I'll look into that and report back.
Stefan
PATCH 2/2 clk: initial clock driver for TWL6030
In reply to Stefan Assmanndrivers/clk/ti/clk-6030.c
Quoted 132 lines · Stefan Assmann
Quoted 11 lines · Mark Brown
drivers/clk/ti/clk-6030.c line 53
Quoted 6 lines · Stefan Assmann
drivers/clk/ti/clk-6030.c new file +6
-0+static int twl6030_clk32kg_is_prepared (struct clk_hw *hw) +{ +struct twl6030_desc *desc =to_twl6030_desc (hw); + +return desc->enabled; +}Why not just check the register map - can't the register be cached? If that's not possible a comment would be good.
I just took
atl_clk_is_enabled()as template. If you say it's better to read the value, that can be arranged.Quoted 13 lines
drivers/clk/ti/clk-6030.c
Quoted 11 lines
drivers/clk/ti/clk-6030.c new file +10
-0+static int of_twl6030_clk32kg_probe (struct platform_device *pdev) +{ +struct device_node *node = pdev->dev.of_node; +struct clk *clk; +int ret =0 ; + +if (!node) +return -ENODEV ; + + clk =clk_get (&pdev->dev,"clk32kg" );
devm_clk_get()?Changed.
Quoted 5 lines
Review
Quoted 3 lines
(quoted diff) +2
-0+ if (IS_ERR(clk)) + ret = -EPROBE_DEFER;Shouldn't the provided return code be being used?
Changed.
Quoted 8 lines
Review
Quoted 3 lines
(quoted diff) +2
-0+ else + clk_prepare(clk);Why is the clock driver defaulting to enabling the clock, and if it needs to shouldn't it be doing a
prepere_enable()even if the enable happens not to do anything to the hardware? Otherwise child clocks might get confused.Mike advised me to convert the functions from enable/disable to prepare/unprepare because i2c transactions may sleep. That's what I did. The code no longer enables the clock and just prepares it. So IIUC the call to
clk_prepare()should be fine.Quoted 3 lines
The return value is also not being checked.
Changed.
Thanks for your comments Mark, here's a new version of the patch.
Stefan
From
2c52040f33af9dbb41e3e3f355ae154843b277c6Mon Sep 17 00:00:00 2001
From: Stefan Assmann <[email protected]>
Date: Fri, 25 Jul 2014 09:42:27 +0200
Subject: [PATCH] clk: initial clock driver for TWL6030Adding a clock driver for the TI TWL6030. The driver prepares the CLK32KG clock, which is required for the wireless LAN.
v2:
- useMODULE_LICENSE("GPL v2")
- usedevm_clk_get()instead ofclk_get()
- propagate return value ofclk_prepare()
- read prepared state instead of using enabled variableSigned-off-by Stefan Assmann <[email protected]>--- .../devicetree/bindings/clock/ti/twl6030.txt | 4 + drivers/clk/Kconfig | 7 ++ drivers/clk/ti/Makefile | 1 + drivers/clk/ti/clk-6030.c | 133 +++++++++++++++++++++ drivers/mfd/twl-core.c | 3 + 5 files changed, 148 insertions(+)create mode 100644
Documentation/devicetree/bindings/clock/ti/twl6030.txtcreate mode 100644drivers/clk/ti/clk-6030.cDocumentation/devicetree/bindings/clock/ti/twl6030.txt new file +4
-0@@ -0,0 +1,4 @@ +Binding for TI TWL6030. + +Required properties: +- compatible: "ti,twl6030-clk32kg"drivers/clk/Kconfig +7
-0@@ -65,6 +65,13 @@ config COMMON_CLK_S2MPS11 clock. These multi-function devices have two (S2MPS14) or three (S2MPS11, S5M8767) fixed-rate oscillators, clocked at 32KHz each. +config CLK_TWL6030 + tristate "Clock driver for twl6030" + depends on TWL4030_CORE + ---help--- + Enable the TWL6030 clock CLK32KG which is disabled by default. + Needed on the Pandaboard for the wireless LAN. + config CLK_TWL6040 tristate "External McPDM functional clock from twl6040" depends on TWL6040_COREdrivers/clk/ti/Makefile +1
-0@@ -10,4 +10,5 @@ obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \ clk-dra7-atl.o obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o +obj-$(CONFIG_CLK_TWL6030) += $(clk-common) clk-6030.o endifdrivers/clk/ti/clk-6030.c new file +0
-0
Please change the filename to something like clk-twl6030.c. clk-\d+ filenames basically denote a SoC under TI clock driver structure.
drivers/clk/ti/clk-6030.c line 2
Quoted 3 lines
drivers/clk/ti/clk-6030.c new file +2
-0@@ -0,0 +1,133 @@ +/* +* drivers/clk/ti/clk-6030.c
Replace this with some sort of short description instead, see other files under drivers/clk/ti. Having an absolute filename here doesn't really provide anything.
drivers/clk/ti/clk-6030.c line 11
Quoted 9 lines
drivers/clk/ti/clk-6030.c new file +9
-0+* +* Copyright (C) 2014 Stefan Assmann <[email protected]> +* +* 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. +* +* Clock driver for TI twl6030. +*/
A basic comment about this driver, how about trying to make it more generic, as in making it an i2c-clock driver? I guess there are other external chips/boards outside twl6030 family that would be interested in using it.
Quoted 91 lines
drivers/clk/ti/clk-6030.c new file +91
-0+ +#include <linux/module.h> +#include <linux/of.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/i2c/twl.h> +#include <linux/platform_device.h> + +struct twl6030_desc { +struct clk *clk; +struct clk_hw hw; +}; + +static int twl6030_clk32kg_prepare (struct clk_hw *hw) +{ +int ret; + + ret =twl_i2c_write_u8 (TWL_MODULE_PM_RECEIVER , +TWL6030_GRP_CON <<TWL6030_CFG_STATE_GRP_SHIFT | +TWL6030_CFG_STATE_ON , +TWL6030_PM_RECEIVER_CLK32KG_CFG_STATE ); + +return ret; +} + +void twl6030_clk32kg_unprepare (struct clk_hw *hw) +{ +twl_i2c_write_u8 (TWL_MODULE_PM_RECEIVER , +TWL6030_GRP_CON <<TWL6030_CFG_STATE_GRP_SHIFT | +TWL6030_CFG_STATE_OFF , +TWL6030_PM_RECEIVER_CLK32KG_CFG_STATE ); +} + +static int twl6030_clk32kg_is_prepared (struct clk_hw *hw) +{ +u8 is_prepared; + +twl_i2c_read_u8 (TWL_MODULE_PM_RECEIVER , &is_prepared, +TWL6030_PM_RECEIVER_CLK32KG_CFG_STATE ); + +return is_prepared &TWL6030_CFG_STATE_ON ; +} + +static const struct clk_ops twl6030_clk32kg_ops = { + .prepare = twl6030_clk32kg_prepare, + .unprepare = twl6030_clk32kg_unprepare, + .is_prepared = twl6030_clk32kg_is_prepared, +}; + +static void __init of_ti_twl6030_clk32kg_setup (struct device_node *node) +{ +struct twl6030_desc *clk_hw =NULL ; +struct clk_init_data init = {0 }; +struct clk_lookup *clookup; +struct clk *clk; + + clookup =kzalloc (sizeof (*clookup),GFP_KERNEL ); +if (!clookup) { +pr_err ("%s: could not allocate clookup\n" , __func__); +return ; + } + clk_hw =kzalloc (sizeof (*clk_hw),GFP_KERNEL ); +if (!clk_hw) { +pr_err ("%s: could not allocate clk_hw\n" , __func__); + goto err_clk_hw; + } + + clk_hw->hw.init = &init; + + init.name = node->name; + init.ops = &twl6030_clk32kg_ops; + init.flags =CLK_IS_ROOT ; + + clk =clk_register (NULL , &clk_hw->hw); +if (!IS_ERR (clk)) { + clookup->con_id =kstrdup ("clk32kg" ,GFP_KERNEL ); + clookup->clk = clk; +clkdev_add (clookup); + +return ; + } + +kfree (clookup); +err_clk_hw: +kfree (clk_hw); +} +CLK_OF_DECLARE (of_ti_twl6030_clk32kg,"ti,twl6030-clk32kg" , of_ti_twl6030_clk32kg_setup); + +static int of_twl6030_clk32kg_probe (struct platform_device *pdev) +{ +struct device_node *node = pdev->dev.of_node;
drivers/clk/ti/clk-6030.c line 112
Quoted 10 lines
drivers/clk/ti/clk-6030.c new file +10
-0+struct clk *clk; + +if (!node) +return -ENODEV ; + + clk =devm_clk_get (&pdev->dev,"clk32kg" ); +if (IS_ERR (clk)) +return PTR_ERR (clk); + +return clk_prepare (clk);
This is plain wrong as pointed out earlier. The driver that uses the clock must enable it.
Quoted 34 lines
drivers/clk/ti/clk-6030.c new file +21
-0+} + +static struct of_device_id of_twl6030_clk32kg_match_tbl[] = { + { .compatible ="ti,twl6030-clk32kg" , }, + {}, +}; +MODULE_DEVICE_TABLE (of, of_twl6030_clk32kg_match_tbl); + +static struct platform_driver twl6030_clk_driver = { + .driver = { + .name ="twl6030-clk32kg" , + .owner =THIS_MODULE , + .of_match_table = of_twl6030_clk32kg_match_tbl, + }, + .probe = of_twl6030_clk32kg_probe, +}; +module_platform_driver (twl6030_clk_driver); + +MODULE_AUTHOR ("Stefan Assmann <[email protected]>" ); +MODULE_DESCRIPTION ("clock driver for TI SoC based boards with twl6030" ); +MODULE_LICENSE ("GPL v2" );drivers/mfd/twl-core.c +1
-0@@ -34,6 +34,7 @@#include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/err.h> #include <linux/device.h> #include <linux/of.h>
drivers/mfd/twl-core.c static void clocks_init(struct device *dev, · line 1017
Quoted 5 lines
drivers/mfd/twl-core.c +2
-0@@ -1012,6 +1013,8 @@ static void clocks_init(struct device *dev,u32 rate;u8 ctrl =HFCLK_FREQ_26_MHZ ; +of_clk_init (NULL ); +
Don't do this please, this is horrible. of_clk_init or alternatives should be called from board/SoC specific context, otherwise you end up calling the init functions multiple times. If you are facing an issue that TI boards do not initialize external clocks properly currently, this is because TI clock driver does its init hierarchically and does not parse the whole DT for clock nodes. I have an experimental patch available I can post for you to try out which provides external clock support on TI boards if you like.
-Tero
Quoted 4 lines
drivers/mfd/twl-core.c +0
-0osc =clk_get (dev,"fck" );if (IS_ERR (osc)) { printk(KERN_WARNING "Skipping twl internal clock init and "
PATCH 2/2 clk: initial clock driver for TWL6030
On 31.07.2014 13:28, Tero Kristo wrote:
[...]
Quoted 8 lines
drivers/clk/ti/clk-6030.c
Quoted 5 lines
drivers/clk/ti/clk-6030.c new file +0
-0Please change the filename to something like
clk-twl6030.c. clk-\d+ filenames basically denote a SoC under TI clock driver structure.
Ok.
Quoted 8 lines
drivers/clk/ti/clk-6030.c line 2
Quoted 4 lines
drivers/clk/ti/clk-6030.c new file +2
-0@@ -0,0 +1,133 @@ +/* +* drivers/clk/ti/clk-6030.c Replace this with some sort of short description instead, see other files under
drivers/clk/ti. Having an absolute filename here doesn't really provide anything.
Ok.
Quoted 11 lines
drivers/clk/ti/clk-6030.c line 11
Quoted 10 lines
drivers/clk/ti/clk-6030.c new file +9
-0+* +* Copyright (C) 2014 Stefan Assmann <[email protected]> +* +* 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. +* +* Clock driver for TI twl6030. +*/
Quoted 4 lines
A basic comment about this driver, how about trying to make it more generic, as in making it an i2c-clock driver? I guess there are other external chips/boards outside twl6030 family that would be interested in using it.
I'll look into that.
[...]
Quoted 8 lines
Quoted 8 lines
drivers/clk/ti/clk-6030.c new file +8
-0+static int of_twl6030_clk32kg_probe (struct platform_device *pdev) +{ +struct device_node *node = pdev->dev.of_node; +struct clk *clk; + +if (!node) +return -ENODEV ; +
Quoted 8 lines
drivers/clk/ti/clk-6030.c line 112
Quoted 5 lines
drivers/clk/ti/clk-6030.c new file +5
-0+ clk =devm_clk_get (&pdev->dev,"clk32kg" ); +if (IS_ERR (clk)) +return PTR_ERR (clk); + +return clk_prepare (clk);This is plain wrong as pointed out earlier. The driver that uses the clock must enable it.
Understood. I'll change it to clk_prepare_enable().
[...]
Quoted 16 lines
Quoted 16 lines
drivers/mfd/twl-core.c +1
-0@@ -34,6 +34,7 @@#include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/err.h> #include <linux/device.h> #include <linux/of.h> @@ -1012,6 +1013,8 @@ static void clocks_init(struct device *dev,u32 rate;u8 ctrl =HFCLK_FREQ_26_MHZ ;
Quoted 11 lines
drivers/mfd/twl-core.c static void clocks_init(struct device *dev, · line 1017
Quoted 2 lines
drivers/mfd/twl-core.c +2
-0+of_clk_init (NULL ); +Don't do this please, this is horrible.
of_clk_initor alternatives should be called from board/SoC specific context, otherwise you end up calling the init functions multiple times. If you are facing an issue that TI boards do not initialize external clocks properly currently, this is because TI clock driver does its init hierarchically and does not parse the whole DT for clock nodes. I have an experimental patch available I can post for you to try out which provides external clock support on TI boards if you like.
If you could provide that patch that'll be great.
Thanks for the comments Tero.
Stefan
PATCH 2/2 clk: initial clock driver for TWL6030
<snip>
Quoted 17 lines
Quoted 8 lines
Quoted 8 lines
drivers/clk/ti/clk-6030.c new file +8
-0+static int of_twl6030_clk32kg_probe (struct platform_device *pdev) +{ +struct device_node *node = pdev->dev.of_node; +struct clk *clk; + +if (!node) +return -ENODEV ; +Quoted 8 lines
drivers/clk/ti/clk-6030.c line 112
Quoted 5 lines
drivers/clk/ti/clk-6030.c new file +5
-0+ clk =devm_clk_get (&pdev->dev,"clk32kg" ); +if (IS_ERR (clk)) +return PTR_ERR (clk); + +return clk_prepare (clk);This is plain wrong as pointed out earlier. The driver that uses the clock must enable it.
Quoted 1 line
Understood. I'll change it to
clk_prepare_enable().
Nono, remove it completely from here. The clock driver should not enable itself by default. The clock itself has some sort of customer somewhere (like am33xx-wifi driver), which should request for the clock and enable it only when needed.
-Tero
PATCH 2/2 clk: initial clock driver for TWL6030
In reply to Stefan AssmannQuoted 20 lines · Stefan Assmann
Adding a clock driver for the TI TWL6030. The driver prepares the CLK32KG clock, which is required for the wireless LAN.
Signed-off-by Stefan Assmann <[email protected]>--- .../devicetree/bindings/clock/ti/twl6030.txt | 4 + drivers/clk/Kconfig | 7 + drivers/clk/ti/Makefile | 1 + drivers/clk/ti/clk-6030.c | 141 +++++++++++++++++++++ drivers/mfd/twl-core.c | 3 + 5 files changed, 156 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/ti/twl6030.txt create mode 100644 drivers/clk/ti/clk-6030.cDocumentation/devicetree/bindings/clock/ti/twl6030.txt new file +0
-0
Documentation/devicetree/bindings/clock/ti/twl6030.txt line 4
Quoted 4 lines
Documentation/devicetree/bindings/clock/ti/twl6030.txt new file +4
-0@@ -0,0 +1,4 @@ +Binding for TI TWL6030. + +Required properties: +- compatible: "ti,twl6030-clk32kg"
This is not really helping out. Where would you put this compatible? How it is related to twl6030?
Quoted 5 lines
drivers/clk/Kconfig +0
-0
drivers/clk/Kconfig config COMMON_CLK_S2MPS11 · line 73
Quoted 9 lines
drivers/clk/Kconfig +6
-0@@ -65,6 +65,13 @@ config COMMON_CLK_S2MPS11 clock. These multi-function devices have two (S2MPS14) or three (S2MPS11, S5M8767) fixed-rate oscillators, clocked at 32KHz each. +config CLK_TWL6030 + tristate "Clock driver for twl6030" + depends on TWL4030_CORE + ---help--- + Enable the TWL6030 clock CLK32KG which is disabled by default. + Needed on the Pandaboard for the wireless LAN.
This is not relevant information. I'm sure the CLK32KG from twl6030 can be or is used for other purposes on other boards.
Quoted 46 lines
drivers/clk/Kconfig +1
-0+ config CLK_TWL6040 tristate "External McPDM functional clock from twl6040" depends on TWL6040_COREdrivers/clk/ti/Makefile +1
-0@@ -10,4 +10,5 @@ obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \ clk-dra7-atl.o obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o +obj-$(CONFIG_CLK_TWL6030) += $(clk-common) clk-6030.o endifdrivers/clk/ti/clk-6030.c new file +26
-0@@ -0,0 +1,141 @@ +/* +* drivers/clk/ti/clk-6030.c +* +* Copyright (C) 2014 Stefan Assmann <[email protected]> +* +* 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. +* +* Clock driver for ti twl6030. +*/ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/i2c/twl.h> +#include <linux/platform_device.h> + +struct twl6030_desc { +struct clk *clk; +struct clk_hw hw; +bool enabled; +}; + +#define to_twl6030_desc (_hw) container_of(_hw, struct twl6030_desc, hw)
drivers/clk/ti/clk-6030.c line 36
Quoted 10 lines
drivers/clk/ti/clk-6030.c new file +10
-0+ +static int twl6030_clk32kg_prepare (struct clk_hw *hw) +{ +struct twl6030_desc *desc =to_twl6030_desc (hw); +int ret; + + ret =twl_i2c_write_u8 (TWL_MODULE_PM_RECEIVER , +TWL6030_GRP_CON <<TWL6030_CFG_STATE_GRP_SHIFT | +TWL6030_CFG_STATE_ON , +TWL6030_PM_RECEIVER_CLK32KG_CFG_STATE );
What is going to happen if someone ask for this clock before the twl-core is initialized?
Quoted 72 lines
drivers/clk/ti/clk-6030.c new file +72
-0+if (ret ==0 ) + desc->enabled = true; + +return ret; +} +void twl6030_clk32kg_unprepare (struct clk_hw *hw) +{ +struct twl6030_desc *desc =to_twl6030_desc (hw); + +twl_i2c_write_u8 (TWL_MODULE_PM_RECEIVER , +TWL6030_GRP_CON <<TWL6030_CFG_STATE_GRP_SHIFT | +TWL6030_CFG_STATE_OFF , +TWL6030_PM_RECEIVER_CLK32KG_CFG_STATE ); + desc->enabled = false; +} + +static int twl6030_clk32kg_is_prepared (struct clk_hw *hw) +{ +struct twl6030_desc *desc =to_twl6030_desc (hw); + +return desc->enabled; +} + +static const struct clk_ops twl6030_clk32kg_ops = { + .prepare = twl6030_clk32kg_prepare, + .unprepare = twl6030_clk32kg_unprepare, + .is_prepared = twl6030_clk32kg_is_prepared, +}; + +static void __init of_ti_twl6030_clk32kg_setup (struct device_node *node) +{ +struct twl6030_desc *clk_hw =NULL ; +struct clk_init_data init = {0 }; +struct clk_lookup *clookup; +struct clk *clk; + + clookup =kzalloc (sizeof (*clookup),GFP_KERNEL ); +if (!clookup) { +pr_err ("%s: could not allocate clookup\n" , __func__); +return ; + } + clk_hw =kzalloc (sizeof (*clk_hw),GFP_KERNEL ); +if (!clk_hw) { +pr_err ("%s: could not allocate clk_hw\n" , __func__); + goto err_clk_hw; + } + + clk_hw->hw.init = &init; + + init.name = node->name; + init.ops = &twl6030_clk32kg_ops; + init.flags =CLK_IS_ROOT ; + + clk =clk_register (NULL , &clk_hw->hw); +if (!IS_ERR (clk)) { + clookup->con_id =kstrdup ("clk32kg" ,GFP_KERNEL ); + clookup->clk = clk; +clkdev_add (clookup); + +return ; + } + +kfree (clookup); +err_clk_hw: +kfree (clk_hw); +} +CLK_OF_DECLARE (of_ti_twl6030_clk32kg,"ti,twl6030-clk32kg" , of_ti_twl6030_clk32kg_setup); + +static int of_twl6030_clk32kg_probe (struct platform_device *pdev) +{ +struct device_node *node = pdev->dev.of_node; +struct clk *clk;
drivers/clk/ti/clk-6030.c line 118
Quoted 10 lines
drivers/clk/ti/clk-6030.c new file +10
-0+int ret =0 ; + +if (!node) +return -ENODEV ; + + clk =clk_get (&pdev->dev,"clk32kg" ); +if (IS_ERR (clk)) + ret = -EPROBE_DEFER ; +else +clk_prepare (clk);
Why would you do this? The point of a clock provider is that you can enable/disable the clock on demand. Here you enable the clock and leave it enabled for the rest of the time...
clk-dra7-atl deals with similar issue
drivers/clk/ti/clk-6030.c line 124
Quoted 6 lines
drivers/clk/ti/clk-6030.c new file +6
-0+ +return ret; +} + +static struct of_device_id of_twl6030_clk32kg_match_tbl[] = { + { .compatible ="ti,twl6030-clk32kg" , },
Hrm, not sure if this is correct. you have "ti,twl6030-clk32kg" as compatible for the platform driver _and_ you have the same "ti,twl6030-clk32kg" compatible for the declared clock.
This does not seams right.
I think you should not have compatible for the platform driver at all, rather you need to create the needed platform device in the twl-core to probe the driver, then look up for the clock node.
I think in terms of HW setup the Palmas clock is the closest to twl6030's 32K clocks. It might worth taking a look at that for hints. It is not using CLK_OF_DECLARE() since it is external chip, but it does the job.
Quoted 30 lines
drivers/clk/ti/clk-6030.c new file +17
-0+ {}, +}; +MODULE_DEVICE_TABLE (of, of_twl6030_clk32kg_match_tbl); + +static struct platform_driver twl6030_clk_driver = { + .driver = { + .name ="twl6030-clk32kg" , + .owner =THIS_MODULE , + .of_match_table = of_twl6030_clk32kg_match_tbl, + }, + .probe = of_twl6030_clk32kg_probe, +}; +module_platform_driver (twl6030_clk_driver); + +MODULE_AUTHOR ("Stefan Assmann <[email protected]>" ); +MODULE_DESCRIPTION ("clock driver for TI SoC based boards with twl6030" ); +MODULE_LICENSE ("GPL" );drivers/mfd/twl-core.c +1
-0@@ -34,6 +34,7 @@#include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/err.h> #include <linux/device.h> #include <linux/of.h>
drivers/mfd/twl-core.c static void clocks_init(struct device *dev, · line 1017
Quoted 5 lines
drivers/mfd/twl-core.c +2
-0@@ -1012,6 +1013,8 @@ static void clocks_init(struct device *dev,u32 rate;u8 ctrl =HFCLK_FREQ_26_MHZ ; +of_clk_init (NULL ); +
I don't think this is in the right place. twl-core should not call a generic clk init function.
Quoted 4 lines
drivers/mfd/twl-core.c +0
-0osc =clk_get (dev,"fck" );if (IS_ERR (osc)) { printk(KERN_WARNING "Skipping twl internal clock init and "
Signature · 1 line
P?ter
PATCH 2/2 clk: initial clock driver for TWL6030
Quoted 15 lines · Peter Ujfalusi
Quoted 14 lines · Stefan Assmann
Adding a clock driver for the TI TWL6030. The driver prepares the CLK32KG clock, which is required for the wireless LAN.
Signed-off-by Stefan Assmann <[email protected]>--- .../devicetree/bindings/clock/ti/twl6030.txt | 4 + drivers/clk/Kconfig | 7 + drivers/clk/ti/Makefile | 1 + drivers/clk/ti/clk-6030.c | 141 +++++++++++++++++++++ drivers/mfd/twl-core.c | 3 + 5 files changed, 156 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/ti/twl6030.txt create mode 100644 drivers/clk/ti/clk-6030.c
Quoted 14 lines
Documentation/devicetree/bindings/clock/ti/twl6030.txt line 4
Quoted 10 lines
Documentation/devicetree/bindings/clock/ti/twl6030.txt new file +4
-0@@ -0,0 +1,4 @@ +Binding for TI TWL6030. + +Required properties: +- compatible: "ti,twl6030-clk32kg"This is not really helping out. Where would you put this compatible? How it is related to twl6030?
Just making a start, I'll see if I can make it more useful.
Quoted 9 lines
Quoted 9 lines
drivers/clk/Kconfig +0
-0@@ -65,6 +65,13 @@ config COMMON_CLK_S2MPS11 clock. These multi-function devices have two (S2MPS14) or three (S2MPS11, S5M8767) fixed-rate oscillators, clocked at 32KHz each.
Quoted 9 lines
drivers/clk/Kconfig config COMMON_CLK_S2MPS11 · line 73
Quoted 6 lines
drivers/clk/Kconfig +6
-0+config CLK_TWL6030 + tristate "Clock driver for twl6030" + depends on TWL4030_CORE + ---help--- + Enable the TWL6030 clock CLK32KG which is disabled by default. + Needed on the Pandaboard for the wireless LAN.This is not relevant information. I'm sure the CLK32KG from twl6030 can be or is used for other purposes on other boards.
I'll remove it.
Quoted 4 lines
Quoted 4 lines
drivers/clk/Kconfig +4
-0+static int twl6030_clk32kg_prepare(struct clk_hw *hw) +{ + struct twl6030_desc *desc = to_twl6030_desc(hw); + int ret;
Quoted 8 lines
drivers/clk/Kconfig config COMMON_CLK_S2MPS11
Quoted 5 lines
drivers/clk/Kconfig +5
-0+ + ret = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, + TWL6030_GRP_CON << TWL6030_CFG_STATE_GRP_SHIFT | + TWL6030_CFG_STATE_ON, + TWL6030_PM_RECEIVER_CLK32KG_CFG_STATE);What is going to happen if someone ask for this clock before the twl-core is initialized?
Originally in of_twl6030_clk32kg_probe() clk_get() would be called and that would only succeed after of_clk_init() got called in twl_probe(). Tero already pointed out that it should not be done that way.
Quoted 19 lines
Quoted 4 lines
drivers/clk/Kconfig +4
-0+static int of_twl6030_clk32kg_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct clk *clk;drivers/clk/Kconfig
Quoted 10 lines
drivers/clk/Kconfig +10
-0+ int ret = 0; + + if (!node) + return -ENODEV; + + clk = clk_get(&pdev->dev, "clk32kg"); + if (IS_ERR(clk)) + ret = -EPROBE_DEFER; + else + clk_prepare(clk);Why would you do this? The point of a clock provider is that you can enable/disable the clock on demand. Here you enable the clock and leave it enabled for the rest of the time...
Quoted 1 line
clk-dra7-atl deals with similar issue
The idea is to enable the clock by default to get the wifi working. Sorry if I got it wrong.
Quoted 13 lines
drivers/clk/Kconfig
Quoted 7 lines
drivers/clk/Kconfig +6
-0+ + return ret; +} + +static struct of_device_id of_twl6030_clk32kg_match_tbl[] = { + { .compatible = "ti,twl6030-clk32kg", },Hrm, not sure if this is correct. you have "ti,twl6030-clk32kg" as compatible for the platform driver _and_ you have the same "ti,twl6030-clk32kg" compatible for the declared clock.
This does not seams right.
Quoted 7 lines
I think you should not have compatible for the platform driver at all, rather you need to create the needed platform device in the twl-core to probe the driver, then look up for the clock node.
I think in terms of HW setup the Palmas clock is the closest to twl6030's 32K clocks. It might worth taking a look at that for hints. It is not using
CLK_OF_DECLARE()since it is external chip, but it does the job.
Thanks for the hint I'll look at that driver for improvements.
Quoted 9 lines
drivers/clk/Kconfig static void clocks_init(struct device *dev, · line 1017
Quoted 6 lines
drivers/clk/Kconfig +2
-0@@ -1012,6 +1013,8 @@ static void clocks_init(struct device *dev, u32 rate; u8 ctrl = HFCLK_FREQ_26_MHZ; + of_clk_init(NULL); +I don't think this is in the right place. twl-core should not call a generic clk init function.
Tero pointed that out already. Problem is that the clock doesn't show up otherwise. An experimental patch from Tero might help, he offered to post it.
Thanks for the comments Peter.
Stefan
PATCH 2/2 clk: initial clock driver for TWL6030
Quoted 8 lines · Stefan Assmann
Quoted 5 lines
Why would you do this? The point of a clock provider is that you can enable/disable the clock on demand. Here you enable the clock and leave it enabled for the rest of the time...
clk-dra7-atl deals with similar issue
The idea is to enable the clock by default to get the wifi working. Sorry if I got it wrong.
You should have a clock driver for the 32K clock. The wifi driver should request and manage it's clocks via the clock API.
Signature · 1 line
P?ter
PATCH 2/2 clk: initial clock driver for TWL6030
Quoted 5 lines · Peter Ujfalusi
Quoted 4 lines · Stefan Assmann
Quoted 4 lines
Why would you do this? The point of a clock provider is that you can enable/disable the clock on demand. Here you enable the clock and leave it enabled for the rest of the time...
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
clk-dra7-atl deals with similar issue
The idea is to enable the clock by default to get the wifi working. Sorry if I got it wrong.
You should have a clock driver for the 32K clock. The wifi driver should request and manage it's clocks via the clock API.
If the clock does not get enabled the wifi driver wl12xx doesn't even get probed. Which is my initial problem. Maybe I need to figure that out first.
Stefan
PATCH 2/2 clk: initial clock driver for TWL6030
Quoting Stefan Assmann (2014-07-31 07:05:43)
Quoted 11 lines · Peter Ujfalusi
Quoted 10 lines · Stefan Assmann
Quoted 8 lines
Quoted 5 lines
Why would you do this? The point of a clock provider is that you can enable/disable the clock on demand. Here you enable the clock and leave it enabled for the rest of the time...
clk-dra7-atl deals with similar issue
The idea is to enable the clock by default to get the wifi working. Sorry if I got it wrong.
Quoted 7 lines
Quoted 3 lines
You should have a clock driver for the 32K clock. The wifi driver should request and manage it's clocks via the clock API.
If the clock does not get enabled the wifi driver wl12xx doesn't even get probed. Which is my initial problem. Maybe I need to figure that out first.
Sounds like the wifi driver's probe is missing something like:
"""
#include <linux/clk.h>
int ret;
struct clk *clk32k = clk_get(...);
if (IS_ERR(clk32k))
explode();
ret = clk_prepare_enable(clk32k);
if (ret)
explode();
"""
Regards,
Mike
Quoted 2 lines
Stefan
PATCH 2/2 clk: initial clock driver for TWL6030
Quoted 16 lines · Mike Turquette
Quoting Stefan Assmann (2014-07-31 07:05:43)
Quoted 15 lines · Peter Ujfalusi
Quoted 13 lines · Stefan Assmann
Quoted 8 lines
Quoted 5 lines
Why would you do this? The point of a clock provider is that you can enable/disable the clock on demand. Here you enable the clock and leave it enabled for the rest of the time...
clk-dra7-atl deals with similar issue
The idea is to enable the clock by default to get the wifi working. Sorry if I got it wrong.
You should have a clock driver for the 32K clock. The wifi driver should request and manage it's clocks via the clock API.
Quoted 5 lines
Quoted 3 lines
If the clock does not get enabled the wifi driver wl12xx doesn't even get probed. Which is my initial problem. Maybe I need to figure that out first.
Sounds like the wifi driver's probe is missing something like:
Thanks for the example Mike, but the issue is that the wifi drivers probe function doesn't even get called without the clock being powered/enabled. I've instrumented do_one_initcall() to verify this. With the clock being enabled I see:
[ 19.693511] init/main.c do_one_initcall:792 initcall wl1271_init+0x0/0x38 [wlcore_sdio] [ 20.993347] init/main.c do_one_initcall:792 initcall wl12xx_driver_init+0x0/0x14 [wl12xx]
If the clock is kept disabled none of the calls is made and we never get to wl12xx_probe().
The device might not be discoverable without the clock.
Maybe we should rethink the idea of doing that single register write to enable the device in twl-core code, if the TWL6030 is present.
Alternatively this could be done by u-boot. Seems like something that should have been done by firmware upfront.
Stefan
Quoted 22 lines
"""
#include <linux/clk.h>int ret;
struct clk *clk32k =
clk_get(...);if (
IS_ERR(clk32k))explode();ret =
clk_prepare_enable(clk32k);if (ret)
explode();"""
Regards,
MikeQuoted 2 lines
Stefan
Mark Brown
maintainerPATCH 2/2 clk: initial clock driver for TWL6030
Quoted 9 lines · Stefan Assmann
probe function doesn't even get called without the clock being powered/enabled. I've instrumented
do_one_initcall()to verify this. With the clock being enabled I see:[ 19.693511] init/main.c do_one_initcall:792 initcall wl1271_init+0x0/0x38 [wlcore_sdio] [ 20.993347] init/main.c do_one_initcall:792 initcall wl12xx_driver_init+0x0/0x14 [wl12xx]If the clock is kept disabled none of the calls is made and we never get to
wl12xx_probe().
The device might not be discoverable without the clock.
Quoted 5 lines
Maybe we should rethink the idea of doing that single register write to enable the device in twl-core code, if the TWL6030 is present.
Alternatively this could be done by u-boot. Seems like something that should have been done by firmware upfront.
If this is a SDIO device please search the lists for discussion on how
to handle enabling required resources for them - Ulf was working on
something generic for that.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140801/82690b08/attachment.sig>