* Re: [PATCHv2 02/16] iommu/omap: omap_iommu_attach() should return ENODEV, not NULL
From: Laurent Pinchart @ 2014-02-26 2:05 UTC (permalink / raw)
To: Suman Anna
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Tony Lindgren,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-omap-u79uwXL29TY76Z2rM5mHXA, Florian Vaussard
In-Reply-To: <530D19E3.9030407-l0cyMroinI0@public.gmane.org>
Hi Suman,
On Tuesday 25 February 2014 16:32:03 Suman Anna wrote:
> On 02/25/2014 03:13 PM, Laurent Pinchart wrote:
> > On Thursday 13 February 2014 12:15:33 Suman Anna wrote:
> >> From: Florian Vaussard <florian.vaussard-p8DiymsW2f8@public.gmane.org>
> >>
> >> omap_iommu_attach() returns NULL or ERR_PTR in case of error, but
> >> omap_iommu_attach_dev() only checks for IS_ERR. Thus a NULL return value
> >> (in case driver_find_device fails) will cause the kernel to panic when
> >> omap_iommu_attach_dev() dereferences the pointer.
> >>
> >> In such case, omap_iommu_attach() should return ENODEV, not NULL.
> >>
> >> Signed-off-by: Florian Vaussard <florian.vaussard-p8DiymsW2f8@public.gmane.org>
> >> Acked-by: Suman Anna <s-anna-l0cyMroinI0@public.gmane.org>
> >> ---
> >>
> >> drivers/iommu/omap-iommu.c | 4 ++--
> >> 1 file changed, 2 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
> >> index fff2ffd..6272c36 100644
> >> --- a/drivers/iommu/omap-iommu.c
> >> +++ b/drivers/iommu/omap-iommu.c
> >> @@ -863,7 +863,7 @@ static int device_match_by_alias(struct device *dev,
> >> void *data) **/
> >>
> >> static struct omap_iommu *omap_iommu_attach(const char *name, u32
> >> *iopgd)
> >> {
> >> - int err = -ENOMEM;
> >> + int err = -ENODEV;
> >> struct device *dev;
> >> struct omap_iommu *obj;
> >>
> >> @@ -871,7 +871,7 @@ static struct omap_iommu *omap_iommu_attach(const
> >> char *name, u32 *iopgd)
> >> (void *)name,
> >> device_match_by_alias);
> >> if (!dev)
> >> - return NULL;
> >> + return ERR_PTR(err);
> >
> > I would return ERR_PTR(-ENODEV) here, and remove the initialization at
> > declaration of err above.
>
> The initialization at the beginning is also serving one another exit
> path (a check for try_module_get), where err is not being set. If the
> initialization is removed, then the err has to be set explicitly at the
> other place. Let me know if you still want this changed.
The return value of iommu_enable() is unconditionally stored in err before the
try_module_get() call, so that code patch is buggy anyway and should be fixed.
I would still remove the initialization at declaration and assign -ENODEV to
err explicitly when try_module_get() fails before the goto err_module.
> >> obj = to_iommu(dev);
--
Regards,
Laurent Pinchart
^ permalink raw reply
* RE: [PATCH v11 00/15] Add power management support for mxs phy
From: Peter Chen @ 2014-02-26 1:59 UTC (permalink / raw)
To: Peter Chen, balbi@ti.com, shawn.guo@linaro.org,
robh+dt@kernel.org, grant.likely@linaro.org, pawel.moll@arm.com,
mark.rutland@arm.com
Cc: linux-usb@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
festevam@gmail.com, marex@denx.de, kernel@pengutronix.de,
m.grzeschik@pengutronix.de, Frank.Li@freescale.com,
gregkh@linuxfoundation.org, devicetree@vger.kernel.org,
linux-doc@vger.kernel.org
In-Reply-To: <1393208467-6355-1-git-send-email-peter.chen@freescale.com>
Hi Mark,
If you think the dt binding doc (1/15 and 4/15) are ok to push,
please ack it. In that case, the driver maintainer can queue
the driver patches, thanks.
Peter
> The serial adds power management support for MXS PHY, it includes:
>
> - Add one PHY API .set_wakeup, and related API implementation at mxs phy
> driver
> - misc changes and bug fixes for mxs phy to support low power mode and
> wakeup.
>
> It is based on the lastest Greg's usb-next, 3.14-rc3.
>
> Changes for v11:
> - Change the descrition of adding compatible string, and
> add mention that "fsl,imx23-usbphy" is still a fallback
> for other strings. [1/15]
>
> Changes for v10:
> - Nothing related with function change.
> - It adds dt maintainers to To list, and cc devicetree@vger.kernel.org,
> wait dt-maintainer's ack for 1/15, 4/15.
> - Add last three dts patches for reference which have already at Shawn's
> tree.
>
> Changes for v9:
> - Fix the build warning if CONFIG_SUSPEND is not set
>
> Changes for v8:
> - Shawn has already applied two dts patches, so delete them at
> v8 version, http://marc.info/?l=linux-arm-kernel&m=138785188404939&w=2
> - Using of_get_property to avoid imx6 fail at probe when using old DTB
> [5/12]
> - Do not consider failure if alias id is not existed, it can avoid fail
> at probe when using old DTB [8/12]
> - We don't need more changes for [8/12] change due to we use
> "mxs_phy->port_id ==" as condition
>
> Changes for v7:
> - Fixed indentation problem at binding doc [1/14]
> - s/ganranteed/guaranteed, and add explanation for "auto setting" [3/14]
> - add static before SIMPLE_DEV_PM_OPS [13/14]
> - add one patch to change usb device description [7/14]
> - Delete the .nofity_suspend and .notify_resume due to Felipe
> does not agree to add them as PHY API, will use other ways to implement
> them in future.
>
> Changes for v6:
> - Add description for IC bug fixes logic. [9/15]
> - Move is_imx6q_phy and is_imx6sl_phy from [9/15] to [14/15]
> - %s/mxs_phy_clock_switch/mxs_phy_clock_switch_delay to reflect the
> function meaning more precise [15/15]
>
> Changes for v5:
> Add Marc and Michael Grzeschik's commnets
> - typo error at [2/15]
> - sqhash patches which introducing mxs_phy_disconnect_line and fixed but
> at this function. [13/15]
> - Introducing flag MXS_PHY_NEED_IP_FIX who stands for the SoCs who have
> IC fixes. [2/15, 8/15]
> - Delete one patch for low speed connection problem at every rare
> situations due to the root cause has still not found.
>
> Peter Chen (15):
> usb: doc: phy-mxs: Add more compatible strings
> usb: phy-mxs: Add platform judgement code
> usb: phy-mxs: Add auto clock and power setting
> usb: doc: phy-mxs: update binding for adding anatop phandle
> usb: phy-mxs: Add anatop regmap
> usb: phy-mxs: change description of usb device speed
> usb: phy-mxs: Enable IC fixes for related SoCs
> usb: phy-mxs: add controller id
> usb: phy: Add set_wakeup API
> usb: phy-mxs: Add implementation of set_wakeup
> usb: phy-mxs: Add system suspend/resume API
> usb: phy-mxs: Add sync time after controller clear phcd
> ARM: dts: mxs: add mxs phy controller id
> ARM: dts: imx6: add anatop phandle for usbphy
> ARM: dts: imx6: add mxs phy controller id
>
> Documentation/devicetree/bindings/usb/mxs-phy.txt | 8 +-
> arch/arm/boot/dts/imx23.dtsi | 1 +
> arch/arm/boot/dts/imx28.dtsi | 2 +
> arch/arm/boot/dts/imx6qdl.dtsi | 4 +
> arch/arm/boot/dts/imx6sl.dtsi | 4 +
> drivers/usb/phy/phy-mxs-usb.c | 310
> ++++++++++++++++++++-
> include/linux/usb/phy.h | 16 +
> 7 files changed, 330 insertions(+), 15 deletions(-)
>
> --
> 1.7.8
>
^ permalink raw reply
* Re: [PATCH RESEND v2 0/4] clk/exynos convert clock IDs to macros
From: Kukjin Kim @ 2014-02-26 1:05 UTC (permalink / raw)
To: Andrzej Hajda
Cc: linux-arm-kernel, Tomasz Figa, Kukjin Kim, Mike Turquette,
Kyungmin Park, moderated list:OPEN FIRMWARE AND...,
moderated list:ARM/S5P EXYNOS AR...
In-Reply-To: <1393248180-17408-1-git-send-email-a.hajda@samsung.com>
On 02/24/14 22:22, Andrzej Hajda wrote:
> Hi,
>
Hi Andrzej,
> This patch set converts dts files to use macros instead
> of magic numbers or enums to describe clock bindings.
>
> The patch set is rebased on the latest kgene/for-next branch.
>
Thanks.
> The patches are generated by script.
> Many clocks I have verified by hand.
> I have also tested it successfully on exynos4 based board.
>
:)
> This is the 2nd version of the patchset.
> Changes:
> - corrected devicetree mailing list,
> - added comments to include/dt-bindings/clock/exynos4.h for
> clocks present only in particular chip,
> - added tab alignement in headers,
> - added comment to CLK_NR_CLKS,
> - added copyright headers,
> - split long lines in dts,
> - corrected example in bindings/clock/exynos5250-clock.txt, to point
> appropriate clocks.
>
> Regards
> Andrzej
>
> Andrzej Hajda (4):
> ARM: dts: exynos4: convert magic numbers to macros in clock bindings
> ARM: dts: exynos5250: convert magic numbers to macros in clock
> bindings
> ARM: dts: exynos5420: convert magic numbers to macros in clock
> bindings
> ARM: dts: exynos5440: convert magic numbers to macros in clock
> bindings
>
> .../devicetree/bindings/clock/exynos4-clock.txt | 259 +--------------------
> .../devicetree/bindings/clock/exynos5250-clock.txt | 163 +------------
> .../devicetree/bindings/clock/exynos5420-clock.txt | 184 +--------------
> .../devicetree/bindings/clock/exynos5440-clock.txt | 45 +---
> arch/arm/boot/dts/exynos4.dtsi | 73 +++---
> arch/arm/boot/dts/exynos4210.dtsi | 9 +-
> arch/arm/boot/dts/exynos4x12.dtsi | 34 +--
> arch/arm/boot/dts/exynos5250.dtsi | 105 +++++----
> arch/arm/boot/dts/exynos5420.dtsi | 95 ++++----
> arch/arm/boot/dts/exynos5440.dtsi | 33 +--
> 10 files changed, 207 insertions(+), 793 deletions(-)
>
Looks good to me, applied.
Thanks,
Kukjin
^ permalink raw reply
* [PATCHv1 2/2] Documentation: DT: Document rx51-battery binding
From: Sebastian Reichel @ 2014-02-26 0:46 UTC (permalink / raw)
To: Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse
Cc: Jonathan Cameron, Marek Belisko, Rob Herring, Pawel Moll,
Mark Rutland, Ian Campbell, Kumar Gala, Grant Likely,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA, Pali Rohár,
Sebastian Reichel
In-Reply-To: <1393375569-21751-1-git-send-email-sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
Add devicetree binding documentation for rx51-battery,
which is a simple A/D converter consumer.
Signed-off-by: Sebastian Reichel <sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
---
.../devicetree/bindings/power/rx51-battery.txt | 25 ++++++++++++++++++++++
1 file changed, 25 insertions(+)
create mode 100644 Documentation/devicetree/bindings/power/rx51-battery.txt
diff --git a/Documentation/devicetree/bindings/power/rx51-battery.txt b/Documentation/devicetree/bindings/power/rx51-battery.txt
new file mode 100644
index 0000000..9043845
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/rx51-battery.txt
@@ -0,0 +1,25 @@
+Binding for Nokia N900 battery
+
+The Nokia N900 battery status can be read via the TWL4030's A/D converter.
+
+Required properties:
+- compatible: Should contain one of the following:
+ * "nokia,n900-battery"
+- io-channels: Should contain IIO channel specifiers
+ for each element in io-channel-names.
+- io-channel-names: Should contain the following values:
+ * "temp" - The ADC channel for temperature reading
+ * "bsi" - The ADC channel for battery size identification
+ * "vbat" - The ADC channel to measure the battery voltage
+
+Example from Nokia N900:
+
+battery: n900-battery {
+ compatible = "nokia,n900-battery";
+ io-channels = <&twl4030_madc 0>,
+ <&twl4030_madc 4>,
+ <&twl4030_madc 12>;
+ io-channel-names = "temp",
+ "bsi",
+ "vbat";
+};
--
1.8.5.3
^ permalink raw reply related
* [PATCHv1 1/2] rx51_battery: convert to iio consumer
From: Sebastian Reichel @ 2014-02-26 0:46 UTC (permalink / raw)
To: Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse
Cc: Jonathan Cameron, Marek Belisko, Rob Herring, Pawel Moll,
Mark Rutland, Ian Campbell, Kumar Gala, Grant Likely,
linux-kernel, devicetree, linux-iio, Pali Rohár,
Sebastian Reichel
In-Reply-To: <1393375569-21751-1-git-send-email-sre@debian.org>
Update rx51-battery driver to use the new IIO API of
twl4030-madc and add DT support.
Signed-off-by: Sebastian Reichel <sre@debian.org>
---
drivers/power/rx51_battery.c | 68 +++++++++++++++++++++++++++++---------------
1 file changed, 45 insertions(+), 23 deletions(-)
diff --git a/drivers/power/rx51_battery.c b/drivers/power/rx51_battery.c
index 1bc5857..f7cb58e 100644
--- a/drivers/power/rx51_battery.c
+++ b/drivers/power/rx51_battery.c
@@ -24,34 +24,27 @@
#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/i2c/twl4030-madc.h>
-
-/* RX51 specific channels */
-#define TWL4030_MADC_BTEMP_RX51 TWL4030_MADC_ADCIN0
-#define TWL4030_MADC_BCI_RX51 TWL4030_MADC_ADCIN4
+#include <linux/iio/consumer.h>
+#include <linux/of.h>
struct rx51_device_info {
struct device *dev;
struct power_supply bat;
+ struct iio_channel *channel_temp;
+ struct iio_channel *channel_bsi;
+ struct iio_channel *channel_vbat;
};
/*
* Read ADCIN channel value, code copied from maemo kernel
*/
-static int rx51_battery_read_adc(int channel)
+static int rx51_battery_read_adc(struct iio_channel *channel)
{
- struct twl4030_madc_request req;
-
- req.channels = channel;
- req.do_avg = 1;
- req.method = TWL4030_MADC_SW1;
- req.func_cb = NULL;
- req.type = TWL4030_MADC_WAIT;
- req.raw = true;
-
- if (twl4030_madc_conversion(&req) <= 0)
- return -ENODATA;
-
- return req.rbuf[ffs(channel) - 1];
+ int val, err;
+ err = iio_read_channel_average_raw(channel, &val);
+ if (err < 0)
+ return err;
+ return val;
}
/*
@@ -60,10 +53,12 @@ static int rx51_battery_read_adc(int channel)
*/
static int rx51_battery_read_voltage(struct rx51_device_info *di)
{
- int voltage = rx51_battery_read_adc(TWL4030_MADC_VBAT);
+ int voltage = rx51_battery_read_adc(di->channel_vbat);
- if (voltage < 0)
+ if (voltage < 0) {
+ dev_err(di->dev, "Could not read ADC: %d\n", voltage);
return voltage;
+ }
return 1000 * (10000 * voltage / 1705);
}
@@ -112,7 +107,10 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di)
{
int min = 0;
int max = ARRAY_SIZE(rx51_temp_table2) - 1;
- int raw = rx51_battery_read_adc(TWL4030_MADC_BTEMP_RX51);
+ int raw = rx51_battery_read_adc(di->channel_temp);
+
+ if (raw < 0)
+ dev_err(di->dev, "Could not read ADC: %d\n", raw);
/* Zero and negative values are undefined */
if (raw <= 0)
@@ -146,10 +144,12 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di)
*/
static int rx51_battery_read_capacity(struct rx51_device_info *di)
{
- int capacity = rx51_battery_read_adc(TWL4030_MADC_BCI_RX51);
+ int capacity = rx51_battery_read_adc(di->channel_bsi);
- if (capacity < 0)
+ if (capacity < 0) {
+ dev_err(di->dev, "Could not read ADC: %d\n", capacity);
return capacity;
+ }
return 1280 * (1200 * capacity)/(1024 - capacity);
}
@@ -213,12 +213,25 @@ static int rx51_battery_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, di);
+ di->dev = &pdev->dev;
di->bat.name = dev_name(&pdev->dev);
di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
di->bat.properties = rx51_battery_props;
di->bat.num_properties = ARRAY_SIZE(rx51_battery_props);
di->bat.get_property = rx51_battery_get_property;
+ di->channel_temp = iio_channel_get(di->dev, "temp");
+ if (IS_ERR(di->channel_temp))
+ return PTR_ERR(di->channel_temp);
+
+ di->channel_bsi = iio_channel_get(di->dev, "bsi");
+ if (IS_ERR(di->channel_bsi))
+ return PTR_ERR(di->channel_bsi);
+
+ di->channel_vbat = iio_channel_get(di->dev, "vbat");
+ if (IS_ERR(di->channel_vbat))
+ return PTR_ERR(di->channel_vbat);
+
ret = power_supply_register(di->dev, &di->bat);
if (ret)
return ret;
@@ -235,12 +248,21 @@ static int rx51_battery_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id n900_battery_of_match[] = {
+ {.compatible = "nokia,n900-battery", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, n900_battery_of_match);
+#endif
+
static struct platform_driver rx51_battery_driver = {
.probe = rx51_battery_probe,
.remove = rx51_battery_remove,
.driver = {
.name = "rx51-battery",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(n900_battery_of_match),
},
};
module_platform_driver(rx51_battery_driver);
--
1.8.5.3
^ permalink raw reply related
* [PATCHv1 0/2] Convert rx51-battery to IIO API and add DT support
From: Sebastian Reichel @ 2014-02-26 0:46 UTC (permalink / raw)
To: Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse
Cc: Jonathan Cameron, Marek Belisko, Rob Herring, Pawel Moll,
Mark Rutland, Ian Campbell, Kumar Gala, Grant Likely,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA, Pali Rohár,
Sebastian Reichel
Hi,
This is PATCHv1 for converting rx51-battery to the IIO API
and adding DT support. The patchset compiles and has been
tested on my Nokia N900. It depends on another patchset
converting twl4030-madc to the IIO API:
https://lkml.org/lkml/2014/2/25/627
-- Sebastian
Sebastian Reichel (2):
rx51_battery: convert to iio consumer
Documentation: DT: Document rx51-battery binding
.../devicetree/bindings/power/rx51-battery.txt | 25 ++++++++
drivers/power/rx51_battery.c | 68 ++++++++++++++--------
2 files changed, 70 insertions(+), 23 deletions(-)
create mode 100644 Documentation/devicetree/bindings/power/rx51-battery.txt
--
1.8.5.3
^ permalink raw reply
* [RFCv3 7/7] mfd: twl4030-madc: Move driver to drivers/iio/adc
From: Sebastian Reichel @ 2014-02-26 0:24 UTC (permalink / raw)
To: Sebastian Reichel, Marek Belisko, Jonathan Cameron
Cc: Lee Jones, Samuel Ortiz, Lars-Peter Clausen, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Grant Likely,
linux-kernel, devicetree, linux-iio, Sebastian Reichel
In-Reply-To: <1393374270-20079-1-git-send-email-sre@debian.org>
This is a driver for an A/D converter, which belongs into
drivers/iio/adc.
Signed-off-by: Sebastian Reichel <sre@debian.org>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
drivers/iio/adc/Kconfig | 10 ++++++++++
drivers/iio/adc/Makefile | 1 +
drivers/{mfd => iio/adc}/twl4030-madc.c | 0
drivers/mfd/Kconfig | 10 ----------
drivers/mfd/Makefile | 1 -
5 files changed, 11 insertions(+), 11 deletions(-)
rename drivers/{mfd => iio/adc}/twl4030-madc.c (100%)
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 2209f28..427f75c 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -183,6 +183,16 @@ config TI_AM335X_ADC
Say yes here to build support for Texas Instruments ADC
driver which is also a MFD client.
+config TWL4030_MADC
+ tristate "TWL4030 MADC (Monitoring A/D Converter)"
+ depends on TWL4030_CORE
+ help
+ This driver provides support for Triton TWL4030-MADC. The
+ driver supports both RT and SW conversion methods.
+
+ This driver can also be built as a module. If so, the module will be
+ called twl4030-madc.
+
config TWL6030_GPADC
tristate "TWL6030 GPADC (General Purpose A/D Converter) Support"
depends on TWL4030_CORE
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index ba9a10a..9acf2df 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -20,5 +20,6 @@ obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
+obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c
similarity index 100%
rename from drivers/mfd/twl4030-madc.c
rename to drivers/iio/adc/twl4030-madc.c
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 49bb445..23a8a51 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -935,16 +935,6 @@ config TWL4030_CORE
high speed USB OTG transceiver, an audio codec (on most
versions) and many other features.
-config TWL4030_MADC
- tristate "TI TWL4030 MADC"
- depends on TWL4030_CORE
- help
- This driver provides support for triton TWL4030-MADC. The
- driver supports both RT and SW conversion methods.
-
- This driver can be built as a module. If so it will be
- named twl4030-madc
-
config TWL4030_POWER
bool "TI TWL4030 power resources"
depends on TWL4030_CORE && ARM
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 5aea5ef..c8eb0bc 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -71,7 +71,6 @@ obj-$(CONFIG_MFD_TPS80031) += tps80031.o
obj-$(CONFIG_MENELAUS) += menelaus.o
obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o
-obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o
obj-$(CONFIG_TWL6040_CORE) += twl6040.o
--
1.8.5.3
^ permalink raw reply related
* [RFCv3 6/7] Documentation: DT: Document twl4030-madc binding
From: Sebastian Reichel @ 2014-02-26 0:24 UTC (permalink / raw)
To: Sebastian Reichel, Marek Belisko, Jonathan Cameron
Cc: Lee Jones, Samuel Ortiz, Lars-Peter Clausen, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Grant Likely,
linux-kernel, devicetree, linux-iio, Sebastian Reichel
In-Reply-To: <1393374270-20079-1-git-send-email-sre@debian.org>
Add devicetree binding documentation for twl4030-madc
analog digital converter.
Signed-off-by: Sebastian Reichel <sre@debian.org>
---
.../devicetree/bindings/iio/adc/twl4030-madc.txt | 24 ++++++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt
diff --git a/Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt b/Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt
new file mode 100644
index 0000000..6bdd214
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt
@@ -0,0 +1,24 @@
+* TWL4030 Monitoring Analog to Digital Converter (MADC)
+
+The MADC subsystem in the TWL4030 consists of a 10-bit ADC
+combined with a 16-input analog multiplexer.
+
+Required properties:
+ - compatible: Should contain "ti,twl4030-madc".
+ - interrupts: IRQ line for the MADC submodule.
+ - #io-channel-cells: Should be set to <1>.
+
+Optional properties:
+ - ti,system-uses-second-madc-irq: boolean, set if the second madc irq register
+ should be used, which is intended to be used
+ by Co-Processors (e.g. a modem).
+
+Example:
+
+&twl {
+ madc {
+ compatible = "ti,twl4030-madc";
+ interrupts = <3>;
+ #io-channel-cells = <1>;
+ };
+};
--
1.8.5.3
^ permalink raw reply related
* [RFCv3 5/7] mfd: twl4030-madc: Use twl_i2c_read/write_u16 for 16 bit registers
From: Sebastian Reichel @ 2014-02-26 0:24 UTC (permalink / raw)
To: Sebastian Reichel, Marek Belisko, Jonathan Cameron
Cc: Lee Jones, Samuel Ortiz, Lars-Peter Clausen, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Grant Likely,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA, Sebastian Reichel
In-Reply-To: <1393374270-20079-1-git-send-email-sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
Simplify reading and writing of 16 bit TWL registers in the
driver by using twl_i2c_read_u16 and twl_i2c_write_u16.
Signed-off-by: Sebastian Reichel <sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
---
drivers/mfd/twl4030-madc.c | 39 ++++++++-------------------------------
1 file changed, 8 insertions(+), 31 deletions(-)
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
index c23025b..d19aa3e 100644
--- a/drivers/mfd/twl4030-madc.c
+++ b/drivers/mfd/twl4030-madc.c
@@ -207,25 +207,19 @@ const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
*/
static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
{
- u8 msb, lsb;
+ u16 val;
int ret;
/*
* For each ADC channel, we have MSB and LSB register pair. MSB address
* is always LSB address+1. reg parameter is the address of LSB register
*/
- ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &msb, reg + 1);
+ ret = twl_i2c_read_u16(TWL4030_MODULE_MADC, &val, reg);
if (ret) {
- dev_err(madc->dev, "unable to read MSB register 0x%X\n",
- reg + 1);
- return ret;
- }
- ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &lsb, reg);
- if (ret) {
- dev_err(madc->dev, "unable to read LSB register 0x%X\n", reg);
+ dev_err(madc->dev, "unable to read register 0x%X\n", reg);
return ret;
}
- return (int)(((msb << 8) | lsb) >> 6);
+ return (int)(val >> 6);
}
/*
@@ -571,7 +565,6 @@ static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
int twl4030_madc_conversion(struct twl4030_madc_request *req)
{
const struct twl4030_madc_conversion_method *method;
- u8 ch_msb, ch_lsb;
int ret;
if (!req || !twl4030_madc)
@@ -587,37 +580,21 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
ret = -EBUSY;
goto out;
}
- ch_msb = (req->channels >> 8) & 0xff;
- ch_lsb = req->channels & 0xff;
method = &twl4030_conversion_methods[req->method];
/* Select channels to be converted */
- ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_msb, method->sel + 1);
+ ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels, method->sel);
if (ret) {
dev_err(twl4030_madc->dev,
- "unable to write sel register 0x%X\n", method->sel + 1);
- goto out;
- }
- ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel);
- if (ret) {
- dev_err(twl4030_madc->dev,
- "unable to write sel register 0x%X\n", method->sel + 1);
+ "unable to write sel register 0x%X\n", method->sel);
goto out;
}
/* Select averaging for all channels if do_avg is set */
if (req->do_avg) {
- ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
- ch_msb, method->avg + 1);
+ ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels,
+ method->avg);
if (ret) {
dev_err(twl4030_madc->dev,
"unable to write avg register 0x%X\n",
- method->avg + 1);
- goto out;
- }
- ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
- ch_lsb, method->avg);
- if (ret) {
- dev_err(twl4030_madc->dev,
- "unable to write avg reg 0x%X\n",
method->avg);
goto out;
}
--
1.8.5.3
^ permalink raw reply related
* [RFCv3 4/7] mfd: twl-core: Add twl_i2c_read/write_u16
From: Sebastian Reichel @ 2014-02-26 0:24 UTC (permalink / raw)
To: Sebastian Reichel, Marek Belisko, Jonathan Cameron
Cc: Lee Jones, Samuel Ortiz, Lars-Peter Clausen, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Grant Likely,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA, Sebastian Reichel
In-Reply-To: <1393374270-20079-1-git-send-email-sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
Add a simple twl_i2c_read/write_u16 wrapper over
the twl_i2c_read/write, which is similar to the
twl_i2c_read/write_u8 wrapper.
Signed-off-by: Sebastian Reichel <sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
---
include/linux/i2c/twl.h | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index ade1c06..d2b1670 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -195,6 +195,18 @@ static inline int twl_i2c_read_u8(u8 mod_no, u8 *val, u8 reg) {
return twl_i2c_read(mod_no, val, reg, 1);
}
+static inline int twl_i2c_write_u16(u8 mod_no, u16 val, u8 reg) {
+ val = cpu_to_le16(val);
+ return twl_i2c_write(mod_no, (u8*) &val, reg, 2);
+}
+
+static inline int twl_i2c_read_u16(u8 mod_no, u16 *val, u8 reg) {
+ int ret;
+ ret = twl_i2c_read(mod_no, (u8*) val, reg, 2);
+ *val = le16_to_cpu(*val);
+ return ret;
+}
+
int twl_get_type(void);
int twl_get_version(void);
int twl_get_hfclk_rate(void);
--
1.8.5.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [RFCv3 3/7] mfd: twl4030-madc: Cleanup driver
From: Sebastian Reichel @ 2014-02-26 0:24 UTC (permalink / raw)
To: Sebastian Reichel, Marek Belisko, Jonathan Cameron
Cc: Lee Jones, Samuel Ortiz, Lars-Peter Clausen, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Grant Likely,
linux-kernel, devicetree, linux-iio, Sebastian Reichel
In-Reply-To: <1393374270-20079-1-git-send-email-sre@debian.org>
Some style fixes in twl4030-madc driver.
Reported-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Sebastian Reichel <sre@debian.org>
---
drivers/mfd/twl4030-madc.c | 108 ++++++++++++++++++---------------------
include/linux/i2c/twl4030-madc.h | 2 +-
2 files changed, 51 insertions(+), 59 deletions(-)
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
index 81484ee..c23025b 100644
--- a/drivers/mfd/twl4030-madc.c
+++ b/drivers/mfd/twl4030-madc.c
@@ -49,11 +49,12 @@
#include <linux/iio/iio.h>
-/*
+/**
* struct twl4030_madc_data - a container for madc info
* @dev - pointer to device structure for madc
* @lock - mutex protecting this data structure
* @requests - Array of request struct corresponding to SW1, SW2 and RT
+ * @use_second_irq - IRQ selection (main or co-processor)
* @imr - Interrupt mask register of MADC
* @isr - Interrupt status register of MADC
*/
@@ -62,8 +63,8 @@ struct twl4030_madc_data {
struct mutex lock; /* mutex protecting this data structure */
struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
bool use_second_irq;
- int imr;
- int isr;
+ u8 imr;
+ u8 isr;
};
static int twl4030_madc_read(struct iio_dev *iio_dev,
@@ -157,17 +158,16 @@ twl4030_divider_ratios[16] = {
};
-/*
- * Conversion table from -3 to 55 degree Celcius
- */
-static int therm_tbl[] = {
-30800, 29500, 28300, 27100,
-26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900,
-17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100,
-11600, 11200, 10800, 10400, 10000, 9630, 9280, 8950, 8620, 8310,
-8020, 7730, 7460, 7200, 6950, 6710, 6470, 6250, 6040, 5830,
-5640, 5450, 5260, 5090, 4920, 4760, 4600, 4450, 4310, 4170,
-4040, 3910, 3790, 3670, 3550
+/* Conversion table from -3 to 55 degree Celcius */
+static int twl4030_therm_tbl[] = {
+ 30800, 29500, 28300, 27100,
+ 26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700,
+ 17900, 17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100,
+ 12600, 12100, 11600, 11200, 10800, 10400, 10000, 9630, 9280,
+ 8950, 8620, 8310, 8020, 7730, 7460, 7200, 6950, 6710,
+ 6470, 6250, 6040, 5830, 5640, 5450, 5260, 5090, 4920,
+ 4760, 4600, 4450, 4310, 4170, 4040, 3910, 3790, 3670,
+ 3550
};
/*
@@ -199,7 +199,7 @@ const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
},
};
-/*
+/**
* Function to read a particular channel value.
* @madc - pointer to struct twl4030_madc_data
* @reg - lsb of ADC Channel
@@ -229,7 +229,7 @@ static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
}
/*
- * Return battery temperature
+ * Return battery temperature in degree Celsius
* Or < 0 on failure.
*/
static int twl4030battery_temperature(int raw_volt)
@@ -238,18 +238,18 @@ static int twl4030battery_temperature(int raw_volt)
int temp, curr, volt, res, ret;
volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R;
- /* Getting and calculating the supply current in micro ampers */
+ /* Getting and calculating the supply current in micro amperes */
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
REG_BCICTL2);
if (ret < 0)
return ret;
+
curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10;
/* Getting and calculating the thermistor resistance in ohms */
res = volt * 1000 / curr;
/* calculating temperature */
for (temp = 58; temp >= 0; temp--) {
- int actual = therm_tbl[temp];
-
+ int actual = twl4030_therm_tbl[temp];
if ((actual - res) >= 0)
break;
}
@@ -271,11 +271,12 @@ static int twl4030battery_current(int raw_volt)
else /* slope of 0.88 mV/mA */
return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2;
}
+
/*
* Function to read channel values
* @madc - pointer to twl4030_madc_data struct
* @reg_base - Base address of the first channel
- * @Channels - 16 bit bitmap. If the bit is set, channel value is read
+ * @Channels - 16 bit bitmap. If the bit is set, channel's value is read
* @buf - The channel values are stored here. if read fails error
* @raw - Return raw values without conversion
* value is stored
@@ -286,17 +287,14 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
long channels, int *buf,
bool raw)
{
- int count = 0, count_req = 0, i;
- u8 reg;
+ int count = 0, i;
for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) {
- reg = reg_base + 2 * i;
- buf[i] = twl4030_madc_channel_raw_read(madc, reg);
+ buf[i] = twl4030_madc_channel_raw_read(madc, reg_base + 2 * i);
if (buf[i] < 0) {
- dev_err(madc->dev,
- "Unable to read register 0x%X\n", reg);
- count_req++;
- continue;
+ dev_err(madc->dev, "Unable to read register 0x%X\n",
+ reg_base + 2 * i);
+ return buf[i];
}
if (raw) {
count++;
@@ -307,7 +305,7 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
buf[i] = twl4030battery_current(buf[i]);
if (buf[i] < 0) {
dev_err(madc->dev, "err reading current\n");
- count_req++;
+ return buf[i];
} else {
count++;
buf[i] = buf[i] - 750;
@@ -317,7 +315,7 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
buf[i] = twl4030battery_temperature(buf[i]);
if (buf[i] < 0) {
dev_err(madc->dev, "err reading temperature\n");
- count_req++;
+ return buf[i];
} else {
buf[i] -= 3;
count++;
@@ -338,8 +336,6 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
twl4030_divider_ratios[i].numerator);
}
}
- if (count_req)
- dev_err(madc->dev, "%d channel conversion failed\n", count_req);
return count;
}
@@ -363,13 +359,13 @@ static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id)
madc->imr);
return ret;
}
+
val &= ~(1 << id);
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
if (ret) {
dev_err(madc->dev,
"unable to write imr register 0x%X\n", madc->imr);
return ret;
-
}
return 0;
@@ -432,7 +428,7 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
continue;
ret = twl4030_madc_disable_irq(madc, i);
if (ret < 0)
- dev_dbg(madc->dev, "Disable interrupt failed%d\n", i);
+ dev_dbg(madc->dev, "Disable interrupt failed %d\n", i);
madc->requests[i].result_pending = 1;
}
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
@@ -514,21 +510,17 @@ static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
{
const struct twl4030_madc_conversion_method *method;
int ret = 0;
+
+ if (conv_method != TWL4030_MADC_SW1 && conv_method != TWL4030_MADC_SW2)
+ return -ENOTSUPP;
+
method = &twl4030_conversion_methods[conv_method];
- switch (conv_method) {
- case TWL4030_MADC_SW1:
- case TWL4030_MADC_SW2:
- ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
- TWL4030_MADC_SW_START, method->ctrl);
- if (ret) {
- dev_err(madc->dev,
- "unable to write ctrl register 0x%X\n",
- method->ctrl);
- return ret;
- }
- break;
- default:
- break;
+ ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, TWL4030_MADC_SW_START,
+ method->ctrl);
+ if (ret) {
+ dev_err(madc->dev, "unable to write ctrl register 0x%X\n",
+ method->ctrl);
+ return ret;
}
return 0;
@@ -625,8 +617,8 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
ch_lsb, method->avg);
if (ret) {
dev_err(twl4030_madc->dev,
- "unable to write sel reg 0x%X\n",
- method->sel + 1);
+ "unable to write avg reg 0x%X\n",
+ method->avg);
goto out;
}
}
@@ -667,10 +659,6 @@ out:
}
EXPORT_SYMBOL_GPL(twl4030_madc_conversion);
-/*
- * Return channel value
- * Or < 0 on failure.
- */
int twl4030_get_madc_conversion(int channel_no)
{
struct twl4030_madc_request req;
@@ -705,6 +693,7 @@ static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
int chan, int on)
{
int ret;
+ int regmask;
u8 regval;
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
@@ -714,10 +703,13 @@ static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
TWL4030_BCI_BCICTL1);
return ret;
}
+
+ regmask = (chan == 0) ? TWL4030_BCI_TYPEN : TWL4030_BCI_ITHEN;
if (on)
- regval |= chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
+ regval |= regmask;
else
- regval &= chan ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
+ regval &= ~regmask;
+
ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
regval, TWL4030_BCI_BCICTL1);
if (ret) {
@@ -732,7 +724,7 @@ static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
/*
* Function that sets MADC software power on bit to enable MADC
* @madc - pointer to twl4030_madc_data struct
- * @on - Enable or disable MADC software powen on bit.
+ * @on - Enable or disable MADC software power on bit.
* returns error if i2c read/write fails else 0
*/
static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
@@ -794,7 +786,7 @@ static int twl4030_madc_probe(struct platform_device *pdev)
iio_dev->info = &twl4030_madc_iio_info;
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->channels = twl4030_madc_iio_channels;
- iio_dev->num_channels = 16;
+ iio_dev->num_channels = ARRAY_SIZE(twl4030_madc_iio_channels);
/*
* Phoenix provides 2 interrupt lines. The first one is connected to
diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h
index 01f5951..1c0134d 100644
--- a/include/linux/i2c/twl4030-madc.h
+++ b/include/linux/i2c/twl4030-madc.h
@@ -44,7 +44,7 @@ struct twl4030_madc_conversion_method {
struct twl4030_madc_request {
unsigned long channels;
- u16 do_avg;
+ bool do_avg;
u16 method;
u16 type;
bool active;
--
1.8.5.3
^ permalink raw reply related
* [RFCv3 2/7] mfd: twl4030-madc: Add DT support and convert to IIO framework
From: Sebastian Reichel @ 2014-02-26 0:24 UTC (permalink / raw)
To: Sebastian Reichel, Marek Belisko, Jonathan Cameron
Cc: Lee Jones, Samuel Ortiz, Lars-Peter Clausen, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Grant Likely,
linux-kernel, devicetree, linux-iio, Sebastian Reichel
In-Reply-To: <1393374270-20079-1-git-send-email-sre@debian.org>
This converts twl4030-madc module to use the Industrial IO ADC
framework and adds device tree support.
Signed-off-by: Sebastian Reichel <sre@debian.org>
---
drivers/mfd/twl4030-madc.c | 122 ++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 115 insertions(+), 7 deletions(-)
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
index 5458561..81484ee 100644
--- a/drivers/mfd/twl4030-madc.c
+++ b/drivers/mfd/twl4030-madc.c
@@ -47,6 +47,8 @@
#include <linux/gfp.h>
#include <linux/err.h>
+#include <linux/iio/iio.h>
+
/*
* struct twl4030_madc_data - a container for madc info
* @dev - pointer to device structure for madc
@@ -59,10 +61,74 @@ struct twl4030_madc_data {
struct device *dev;
struct mutex lock; /* mutex protecting this data structure */
struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
+ bool use_second_irq;
int imr;
int isr;
};
+static int twl4030_madc_read(struct iio_dev *iio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct twl4030_madc_data *madc = iio_priv(iio_dev);
+ struct twl4030_madc_request req;
+ int channel = chan->channel;
+ int ret;
+
+ req.method = madc->use_second_irq ? TWL4030_MADC_SW2 : TWL4030_MADC_SW1;
+
+ req.channels = BIT(channel);
+ req.active = false;
+ req.func_cb = NULL;
+ req.type = TWL4030_MADC_WAIT;
+ req.raw = !(mask == IIO_CHAN_INFO_PROCESSED);
+ req.do_avg = (mask == IIO_CHAN_INFO_AVERAGE_RAW);
+
+ ret = twl4030_madc_conversion(&req);
+ if (ret < 0)
+ return ret;
+
+ *val = req.rbuf[channel];
+
+ return IIO_VAL_INT;
+}
+
+static const struct iio_info twl4030_madc_iio_info = {
+ .read_raw = &twl4030_madc_read,
+ .driver_module = THIS_MODULE,
+};
+
+#define TWL4030_ADC_CHANNEL(_channel, _type, _name, _mask) { \
+ .type = _type, \
+ .channel = _channel, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \
+ _mask, \
+ .datasheet_name = _name, \
+ .indexed = 1, \
+}
+
+static const struct iio_chan_spec twl4030_madc_iio_channels[] = {
+ TWL4030_ADC_CHANNEL(0, IIO_VOLTAGE, "ADCIN0", 0),
+ TWL4030_ADC_CHANNEL(1, IIO_TEMP, "ADCIN1",
+ BIT(IIO_CHAN_INFO_PROCESSED)),
+ TWL4030_ADC_CHANNEL(2, IIO_VOLTAGE, "ADCIN2", 0),
+ TWL4030_ADC_CHANNEL(3, IIO_VOLTAGE, "ADCIN3", 0),
+ TWL4030_ADC_CHANNEL(4, IIO_VOLTAGE, "ADCIN4", 0),
+ TWL4030_ADC_CHANNEL(5, IIO_VOLTAGE, "ADCIN5", 0),
+ TWL4030_ADC_CHANNEL(6, IIO_VOLTAGE, "ADCIN6", 0),
+ TWL4030_ADC_CHANNEL(7, IIO_VOLTAGE, "ADCIN7", 0),
+ TWL4030_ADC_CHANNEL(8, IIO_VOLTAGE, "ADCIN8", 0),
+ TWL4030_ADC_CHANNEL(9, IIO_VOLTAGE, "ADCIN9", 0),
+ TWL4030_ADC_CHANNEL(10, IIO_CURRENT, "ADCIN10",
+ BIT(IIO_CHAN_INFO_PROCESSED)),
+ TWL4030_ADC_CHANNEL(11, IIO_VOLTAGE, "ADCIN11", 0),
+ TWL4030_ADC_CHANNEL(12, IIO_VOLTAGE, "ADCIN12", 0),
+ TWL4030_ADC_CHANNEL(13, IIO_VOLTAGE, "ADCIN13", 0),
+ TWL4030_ADC_CHANNEL(14, IIO_VOLTAGE, "ADCIN14", 0),
+ TWL4030_ADC_CHANNEL(15, IIO_VOLTAGE, "ADCIN15", 0),
+};
+
static struct twl4030_madc_data *twl4030_madc;
struct twl4030_prescale_divider_ratios {
@@ -702,28 +768,50 @@ static int twl4030_madc_probe(struct platform_device *pdev)
{
struct twl4030_madc_data *madc;
struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
int irq, ret;
u8 regval;
+ struct iio_dev *iio_dev = NULL;
- if (!pdata) {
+ if (!pdata && !np) {
dev_err(&pdev->dev, "platform_data not available\n");
return -EINVAL;
}
- madc = devm_kzalloc(&pdev->dev, sizeof(*madc), GFP_KERNEL);
- if (!madc)
+
+ iio_dev = devm_iio_device_alloc(&pdev->dev,
+ sizeof(struct twl4030_madc_data));
+ if (!iio_dev) {
+ dev_err(&pdev->dev, "failed allocating iio device\n");
return -ENOMEM;
+ }
+ madc = iio_priv(iio_dev);
madc->dev = &pdev->dev;
+ iio_dev->name = dev_name(&pdev->dev);
+ iio_dev->dev.parent = &pdev->dev;
+ iio_dev->dev.of_node = pdev->dev.of_node;
+ iio_dev->info = &twl4030_madc_iio_info;
+ iio_dev->modes = INDIO_DIRECT_MODE;
+ iio_dev->channels = twl4030_madc_iio_channels;
+ iio_dev->num_channels = 16;
+
/*
* Phoenix provides 2 interrupt lines. The first one is connected to
* the OMAP. The other one can be connected to the other processor such
* as modem. Hence two separate ISR and IMR registers.
*/
- madc->imr = (pdata->irq_line == 1) ?
+ if (pdata)
+ madc->use_second_irq = pdata->irq_line != 1;
+ else
+ madc->use_second_irq = of_property_read_bool(np,
+ "ti,system-uses-second-madc-irq");
+
+ madc->imr = (madc->use_second_irq == 1) ?
TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
- madc->isr = (pdata->irq_line == 1) ?
+ madc->isr = (madc->use_second_irq == 1) ?
TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
+
ret = twl4030_madc_set_power(madc, 1);
if (ret < 0)
return ret;
@@ -768,7 +856,7 @@ static int twl4030_madc_probe(struct platform_device *pdev)
}
}
- platform_set_drvdata(pdev, madc);
+ platform_set_drvdata(pdev, iio_dev);
mutex_init(&madc->lock);
irq = platform_get_irq(pdev, 0);
@@ -780,7 +868,15 @@ static int twl4030_madc_probe(struct platform_device *pdev)
goto err_i2c;
}
twl4030_madc = madc;
+
+ ret = iio_device_register(iio_dev);
+ if (ret) {
+ dev_dbg(&pdev->dev, "could not register iio device\n");
+ goto err_i2c;
+ }
+
return 0;
+
err_i2c:
twl4030_madc_set_current_generator(madc, 0, 0);
err_current_generator:
@@ -790,20 +886,32 @@ err_current_generator:
static int twl4030_madc_remove(struct platform_device *pdev)
{
- struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
+ struct iio_dev *iio_dev = platform_get_drvdata(pdev);
+ struct twl4030_madc_data *madc = iio_priv(iio_dev);
twl4030_madc_set_current_generator(madc, 0, 0);
twl4030_madc_set_power(madc, 0);
+ iio_device_unregister(iio_dev);
+
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id twl_madc_of_match[] = {
+ {.compatible = "ti,twl4030-madc", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, twl_madc_of_match);
+#endif
+
static struct platform_driver twl4030_madc_driver = {
.probe = twl4030_madc_probe,
.remove = twl4030_madc_remove,
.driver = {
.name = "twl4030_madc",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(twl_madc_of_match),
},
};
--
1.8.5.3
^ permalink raw reply related
* [RFCv3 1/7] mfd: twl4030-madc: Use managed resources
From: Sebastian Reichel @ 2014-02-26 0:24 UTC (permalink / raw)
To: Sebastian Reichel, Marek Belisko, Jonathan Cameron
Cc: Lee Jones, Samuel Ortiz, Lars-Peter Clausen, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Grant Likely,
linux-kernel, devicetree, linux-iio, Sebastian Reichel
In-Reply-To: <1393374270-20079-1-git-send-email-sre@debian.org>
Update twl4030-madc driver to use managed resources.
Signed-off-by: Sebastian Reichel <sre@debian.org>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
drivers/mfd/twl4030-madc.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
index 4c583e4..5458561 100644
--- a/drivers/mfd/twl4030-madc.c
+++ b/drivers/mfd/twl4030-madc.c
@@ -702,14 +702,14 @@ static int twl4030_madc_probe(struct platform_device *pdev)
{
struct twl4030_madc_data *madc;
struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev);
- int ret;
+ int irq, ret;
u8 regval;
if (!pdata) {
dev_err(&pdev->dev, "platform_data not available\n");
return -EINVAL;
}
- madc = kzalloc(sizeof(*madc), GFP_KERNEL);
+ madc = devm_kzalloc(&pdev->dev, sizeof(*madc), GFP_KERNEL);
if (!madc)
return -ENOMEM;
@@ -726,7 +726,7 @@ static int twl4030_madc_probe(struct platform_device *pdev)
TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
ret = twl4030_madc_set_power(madc, 1);
if (ret < 0)
- goto err_power;
+ return ret;
ret = twl4030_madc_set_current_generator(madc, 0, 1);
if (ret < 0)
goto err_current_generator;
@@ -770,7 +770,9 @@ static int twl4030_madc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, madc);
mutex_init(&madc->lock);
- ret = request_threaded_irq(platform_get_irq(pdev, 0), NULL,
+
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
twl4030_madc_threaded_irq_handler,
IRQF_TRIGGER_RISING, "twl4030_madc", madc);
if (ret) {
@@ -783,9 +785,6 @@ err_i2c:
twl4030_madc_set_current_generator(madc, 0, 0);
err_current_generator:
twl4030_madc_set_power(madc, 0);
-err_power:
- kfree(madc);
-
return ret;
}
@@ -793,10 +792,8 @@ static int twl4030_madc_remove(struct platform_device *pdev)
{
struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
- free_irq(platform_get_irq(pdev, 0), madc);
twl4030_madc_set_current_generator(madc, 0, 0);
twl4030_madc_set_power(madc, 0);
- kfree(madc);
return 0;
}
--
1.8.5.3
^ permalink raw reply related
* [RFCv3 0/7] Convert twl4030-madc to IIO API and add DT support
From: Sebastian Reichel @ 2014-02-26 0:24 UTC (permalink / raw)
To: Sebastian Reichel, Marek Belisko, Jonathan Cameron
Cc: Lee Jones, Samuel Ortiz, Lars-Peter Clausen, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Grant Likely,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA, Sebastian Reichel
In-Reply-To: <1393193271-16717-1-git-send-email-sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
Hi,
This is RFCv3 for converting twl4030-madc to the IIO API and
adding DT support. The patchset compiles and has been tested
on my Nokia N900.
Changes since RFCv2:
* Use "--find-renames" for the move from mfd/ to iio/adc/ ;)
* Added Acked-by from Lee Jones (MFD subsystem maintainer)
* Fixed issue found by Joe Perches
- twl4030_madc_request.do_avg should be bool instead of u16
* Fixed issues found by Peter Meerwald
- some style issues (e.g. /** instead of /*)
- typos
- usage of u16 read/write
* Tested with converted rx51-battery driver on Nokia N900
TODO:
* Remove twl4030-madc-hwmon in favour of iio-hwmon
This driver is currently only used by board-omap3beagle.c
and board-rx51-peripherals.c. The instanciation in the
rx51 boardcode is a bug, since actually only twl4030-madc
is needed. Thus board-omap3beagle.c needs to be updated to
iio-hwmon and board-rx51-peripherals.c to twl4030-madc.
Both tasks are pretty trivial and twl4030-madc-hwmon can
be removed afterwards :)
* Update twl4030-madc-battery to the IIO API. I guess Marek
will do this update in the near future, since he is currently
writing DT bindings for the driver.
* I updated twl4030-madc-battery already and will send it
in a separate patchset.
* Once all of the above steps happened the old API can be
removed from the driver, which allows some more cleanups.
-- Sebastian
Sebastian Reichel (7):
mfd: twl4030-madc: Use managed resources
mfd: twl4030-madc: Add DT support and convert to IIO framework
mfd: twl4030-madc: Cleanup driver
mfd: twl-core: Add twl_i2c_read/write_u16
mfd: twl4030-madc: Use twl_i2c_read/write_u16 for 16 bit registers
Documentation: DT: Document twl4030-madc binding
mfd: twl4030-madc: Move driver to drivers/iio/adc
.../devicetree/bindings/iio/adc/twl4030-madc.txt | 24 ++
drivers/iio/adc/Kconfig | 10 +
drivers/iio/adc/Makefile | 1 +
drivers/{mfd => iio/adc}/twl4030-madc.c | 278 +++++++++++++--------
drivers/mfd/Kconfig | 10 -
drivers/mfd/Makefile | 1 -
include/linux/i2c/twl.h | 12 +
include/linux/i2c/twl4030-madc.h | 2 +-
8 files changed, 224 insertions(+), 114 deletions(-)
create mode 100644 Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt
rename drivers/{mfd => iio/adc}/twl4030-madc.c (77%)
--
1.8.5.3
^ permalink raw reply
* [PATCH v2 12/12] ARM: dts: add bus clock bsc3_apb for bcm281xx
From: Alex Elder @ 2014-02-26 0:15 UTC (permalink / raw)
To: mturquette-QSEj5FYQhm4dnm+yROfE0A, mporter-QSEj5FYQhm4dnm+yROfE0A,
bcm-xK7y4jjYLqYh9ZMKESR00Q, galak-sgV2jX0FEOL9JmXXK+q4OQ,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg, mark.rutland-5wv7dgnIgG8,
pawel.moll-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1393373752-30875-1-git-send-email-elder-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Add the bus clock named "bsc3_apb" to the list of those provided by
the slave CCU.
Signed-off-by: Alex Elder <elder-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
arch/arm/boot/dts/bcm11351.dtsi | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/bcm11351.dtsi b/arch/arm/boot/dts/bcm11351.dtsi
index 94b36f6..ff56891 100644
--- a/arch/arm/boot/dts/bcm11351.dtsi
+++ b/arch/arm/boot/dts/bcm11351.dtsi
@@ -247,7 +247,8 @@
"bsc1",
"bsc2",
"bsc3",
- "pwm";
+ "pwm",
+ "bsc3_apb";
};
ref_1m_clk: ref_1m {
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 11/12] clk: bcm281xx: define a bus clock
From: Alex Elder @ 2014-02-26 0:15 UTC (permalink / raw)
To: mturquette-QSEj5FYQhm4dnm+yROfE0A, mporter-QSEj5FYQhm4dnm+yROfE0A,
bcm-xK7y4jjYLqYh9ZMKESR00Q, galak-sgV2jX0FEOL9JmXXK+q4OQ,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg, mark.rutland-5wv7dgnIgG8,
pawel.moll-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1393373752-30875-1-git-send-email-elder-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Define the bus clock "bsc3_apb". This bus clock has to be managed
using the CCU policy mechanism, so add the definitions required for
that to the clock and its CCU.
This one bus clock in particular is defined because it is needed
by peripheral clock "bsc3". Our boot loader does not properly
activate "bsc3_apb", and as a result, "bsc3" isn't able to function
properly. With "bsc3_apb" specified as a prerequisite clock for
"bsc3", the latter works correctly.
For now only this one bus clock is defined, because it allows
correct operation of "bsc3". Others can be added later as needed
(and this patch serves to show how that's done).
Signed-off-by: Alex Elder <elder-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
drivers/clk/bcm/clk-bcm281xx.c | 13 ++++++++++++-
include/dt-bindings/clock/bcm281xx.h | 3 ++-
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/bcm/clk-bcm281xx.c b/drivers/clk/bcm/clk-bcm281xx.c
index 71a65a4..d0d3dde 100644
--- a/drivers/clk/bcm/clk-bcm281xx.c
+++ b/drivers/clk/bcm/clk-bcm281xx.c
@@ -321,8 +321,17 @@ static struct peri_clk_data pwm_data = {
.trig = TRIGGER(0x0afc, 15),
};
+static struct bus_clk_data bsc3_apb_data = {
+ .policy = POLICY(0x0048, 4),
+ .gate = HW_SW_GATE(0x0484, 16, 0, 1),
+};
+
static struct ccu_data slave_ccu_data = {
BCM281XX_CCU_COMMON(slave, SLAVE),
+ .policy = {
+ .enable = CCU_LVM_EN(0x0034, 0),
+ .control = CCU_POLICY_CTL(0x000c, 0, 1, 2),
+ },
.kona_clks = {
[BCM281XX_SLAVE_CCU_UARTB] =
KONA_CLK(slave, uartb, peri),
@@ -341,9 +350,11 @@ static struct ccu_data slave_ccu_data = {
[BCM281XX_SLAVE_CCU_BSC2] =
KONA_CLK(slave, bsc2, peri),
[BCM281XX_SLAVE_CCU_BSC3] =
- KONA_CLK(slave, bsc3, peri),
+ KONA_CLK_PREREQ(slave, bsc3, peri, bsc3_apb),
[BCM281XX_SLAVE_CCU_PWM] =
KONA_CLK(slave, pwm, peri),
+ [BCM281XX_SLAVE_CCU_BSC3_APB] =
+ KONA_CLK(slave, bsc3_apb, bus),
[BCM281XX_SLAVE_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
},
};
diff --git a/include/dt-bindings/clock/bcm281xx.h b/include/dt-bindings/clock/bcm281xx.h
index e009694..57591b1 100644
--- a/include/dt-bindings/clock/bcm281xx.h
+++ b/include/dt-bindings/clock/bcm281xx.h
@@ -60,6 +60,7 @@
#define BCM281XX_SLAVE_CCU_BSC2 7
#define BCM281XX_SLAVE_CCU_BSC3 8
#define BCM281XX_SLAVE_CCU_PWM 9
-#define BCM281XX_SLAVE_CCU_CLOCK_COUNT 10
+#define BCM281XX_SLAVE_CCU_BSC3_APB 10
+#define BCM281XX_SLAVE_CCU_CLOCK_COUNT 11
#endif /* _CLOCK_BCM281XX_H */
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 10/12] clk: bcm281xx: add bus clock support
From: Alex Elder @ 2014-02-26 0:15 UTC (permalink / raw)
To: mturquette, mporter, bcm, galak, ijc+devicetree, mark.rutland,
pawel.moll, robh+dt
Cc: bcm-kernel-feedback-list, linux-arm-kernel, devicetree,
linux-kernel
In-Reply-To: <1393373752-30875-1-git-send-email-elder@linaro.org>
Add bus clock support. A bus clock has a subset of the components
present in a peripheral clock (again, all optional): a gate; CCU
policy management bits; and if needed, bits to control hysteresis.
Signed-off-by: Alex Elder <elder@linaro.org>
---
drivers/clk/bcm/clk-kona-setup.c | 96 ++++++++++++++++++++++++++++++++++++--
drivers/clk/bcm/clk-kona.c | 58 +++++++++++++++++++++++
drivers/clk/bcm/clk-kona.h | 8 ++++
3 files changed, 159 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c
index 973053b..f8c7954 100644
--- a/drivers/clk/bcm/clk-kona-setup.c
+++ b/drivers/clk/bcm/clk-kona-setup.c
@@ -76,6 +76,56 @@ static bool clk_requires_trigger(struct kona_clk *bcm_clk)
return divider_exists(div) && !divider_is_fixed(div);
}
+static bool bus_clk_data_offsets_valid(struct kona_clk *bcm_clk)
+{
+ struct bus_clk_data *bus;
+ struct bcm_clk_policy *policy;
+ struct bcm_clk_gate *gate;
+ struct bcm_clk_hyst *hyst;
+ const char *name;
+ u32 limit;
+
+ BUG_ON(bcm_clk->type != bcm_clk_bus);
+ bus = bcm_clk->bus;
+ name = bcm_clk->init_data.name;
+
+ limit = bcm_clk->ccu->range - sizeof(u32);
+ limit = round_down(limit, sizeof(u32));
+
+ policy = &bus->policy;
+ if (policy_exists(policy)) {
+ if (policy->offset > limit) {
+ pr_err("%s: bad policy offset for %s (%u > %u)\n",
+ __func__, name, policy->offset, limit);
+ return false;
+ }
+ }
+
+ gate = &bus->gate;
+ hyst = &bus->hyst;
+ if (gate_exists(gate)) {
+ if (gate->offset > limit) {
+ pr_err("%s: bad gate offset for %s (%u > %u)\n",
+ __func__, name, gate->offset, limit);
+ return false;
+ }
+ if (hyst_exists(hyst)) {
+ if (hyst->offset > limit) {
+ pr_err("%s: bad hysteresis offset for %s "
+ "(%u > %u)\n", __func__,
+ name, hyst->offset, limit);
+ return false;
+ }
+ }
+ } else if (hyst_exists(hyst)) {
+ pr_err("%s: hysteresis but no gate for %s\n", __func__, name);
+ return false;
+ }
+
+
+ return true;
+}
+
static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk)
{
struct peri_clk_data *peri;
@@ -86,15 +136,13 @@ static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk)
struct bcm_clk_sel *sel;
struct bcm_clk_trig *trig;
const char *name;
- u32 range;
u32 limit;
BUG_ON(bcm_clk->type != bcm_clk_peri);
peri = bcm_clk->peri;
name = bcm_clk->init_data.name;
- range = bcm_clk->ccu->range;
- limit = range - sizeof(u32);
+ limit = bcm_clk->ccu->range - sizeof(u32);
limit = round_down(limit, sizeof(u32));
policy = &peri->policy;
@@ -396,6 +444,23 @@ static bool trig_valid(struct bcm_clk_trig *trig, const char *field_name,
return bit_posn_valid(trig->bit, field_name, clock_name);
}
+/* Determine whether the set of bus clock registers are valid. */
+static bool
+bus_clk_data_valid(struct kona_clk *bcm_clk)
+{
+ struct bcm_clk_gate *gate;
+
+ BUG_ON(bcm_clk->type != bcm_clk_bus);
+ if (!bus_clk_data_offsets_valid(bcm_clk))
+ return false;
+
+ gate = &bcm_clk->bus->gate;
+ if (!gate_exists(gate))
+ return true;
+
+ return gate_valid(gate, "gate", bcm_clk->init_data.name);
+}
+
/* Determine whether the set of peripheral clock registers are valid. */
static bool
peri_clk_data_valid(struct kona_clk *bcm_clk)
@@ -493,6 +558,10 @@ peri_clk_data_valid(struct kona_clk *bcm_clk)
static bool kona_clk_valid(struct kona_clk *bcm_clk)
{
switch (bcm_clk->type) {
+ case bcm_clk_bus:
+ if (!bus_clk_data_valid(bcm_clk))
+ return false;
+ break;
case bcm_clk_peri:
if (!peri_clk_data_valid(bcm_clk))
return false;
@@ -663,6 +732,20 @@ static void clk_sel_teardown(struct bcm_clk_sel *sel,
init_data->parent_names = NULL;
}
+static void bus_clk_teardown(struct bus_clk_data *data,
+ struct clk_init_data *init_data)
+{
+ /* Nothing to do */
+}
+
+static int
+bus_clk_setup(struct bus_clk_data *data, struct clk_init_data *init_data)
+{
+ init_data->flags = CLK_IGNORE_UNUSED;
+
+ return 0;
+}
+
static void peri_clk_teardown(struct peri_clk_data *data,
struct clk_init_data *init_data)
{
@@ -689,6 +772,9 @@ static void bcm_clk_teardown(struct kona_clk *bcm_clk)
/* clkdev_remove(&bcm_clk->cl); */
switch (bcm_clk->type) {
+ case bcm_clk_bus:
+ bus_clk_teardown(bcm_clk->data, &bcm_clk->init_data);
+ break;
case bcm_clk_peri:
peri_clk_teardown(bcm_clk->data, &bcm_clk->init_data);
break;
@@ -725,6 +811,10 @@ struct clk *kona_clk_setup(struct kona_clk *bcm_clk)
struct clk *clk = NULL;
switch (bcm_clk->type) {
+ case bcm_clk_bus:
+ if (bus_clk_setup(bcm_clk->data, init_data))
+ return NULL;
+ break;
case bcm_clk_peri:
if (peri_clk_setup(bcm_clk->data, init_data))
return NULL;
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index 37f7861..00db272 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -984,6 +984,36 @@ static int selector_write(struct ccu_data *ccu, struct bcm_clk_gate *gate,
/* Clock operations */
+static int kona_bus_clk_enable(struct clk_hw *hw)
+{
+ struct kona_clk *bcm_clk = to_kona_clk(hw);
+ struct bcm_clk_gate *gate = &bcm_clk->bus->gate;
+
+ return clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, true);
+}
+
+static void kona_bus_clk_disable(struct clk_hw *hw)
+{
+ struct kona_clk *bcm_clk = to_kona_clk(hw);
+ struct bcm_clk_gate *gate = &bcm_clk->bus->gate;
+
+ (void)clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, false);
+}
+
+static int kona_bus_clk_is_enabled(struct clk_hw *hw)
+{
+ struct kona_clk *bcm_clk = to_kona_clk(hw);
+ struct bcm_clk_gate *gate = &bcm_clk->bus->gate;
+
+ return is_clk_gate_enabled(bcm_clk->ccu, gate) ? 1 : 0;
+}
+
+struct clk_ops kona_bus_clk_ops = {
+ .enable = kona_bus_clk_enable,
+ .disable = kona_bus_clk_disable,
+ .is_enabled = kona_bus_clk_is_enabled,
+};
+
static int kona_peri_clk_enable(struct clk_hw *hw)
{
struct kona_clk *bcm_clk = to_kona_clk(hw);
@@ -1142,6 +1172,31 @@ struct clk_ops kona_peri_clk_ops = {
.set_rate = kona_peri_clk_set_rate,
};
+/* Put a bus clock into its initial state */
+static bool __bus_clk_init(struct kona_clk *bcm_clk)
+{
+ struct ccu_data *ccu = bcm_clk->ccu;
+ struct bus_clk_data *bus = bcm_clk->bus;
+ const char *name = bcm_clk->init_data.name;
+
+ BUG_ON(bcm_clk->type != bcm_clk_bus);
+
+ if (!policy_init(ccu, &bus->policy)) {
+ pr_err("%s: error initializing policy for %s\n",
+ __func__, name);
+ return false;
+ }
+ if (!gate_init(ccu, &bus->gate)) {
+ pr_err("%s: error initializing gate for %s\n", __func__, name);
+ return false;
+ }
+ if (!hyst_init(ccu, &bus->hyst)) {
+ pr_err("%s: error initializing hyst for %s\n", __func__, name);
+ return false;
+ }
+ return true;
+}
+
/* Put a peripheral clock into its initial state */
static bool __peri_clk_init(struct kona_clk *bcm_clk)
{
@@ -1246,6 +1301,9 @@ static bool __kona_clk_init(struct kona_clk *bcm_clk)
return false;
switch (bcm_clk->type) {
+ case bcm_clk_bus:
+ ret = __bus_clk_init(bcm_clk);
+ break;
case bcm_clk_peri:
ret = __peri_clk_init(bcm_clk);
break;
diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h
index 27e0913..fdb25c6 100644
--- a/drivers/clk/bcm/clk-kona.h
+++ b/drivers/clk/bcm/clk-kona.h
@@ -389,6 +389,12 @@ struct bcm_clk_trig {
.flags = FLAG(TRIG, EXISTS), \
}
+struct bus_clk_data {
+ struct bcm_clk_policy policy;
+ struct bcm_clk_gate gate;
+ struct bcm_clk_hyst hyst;
+};
+
struct peri_clk_data {
struct bcm_clk_policy policy;
struct bcm_clk_gate gate;
@@ -416,6 +422,7 @@ struct kona_clk {
};
union {
void *data;
+ struct bus_clk_data *bus;
struct peri_clk_data *peri;
};
};
@@ -520,6 +527,7 @@ struct ccu_data {
/* Exported globals */
+extern struct clk_ops kona_bus_clk_ops;
extern struct clk_ops kona_peri_clk_ops;
/* Externally visible functions */
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 09/12] clk: bcm281xx: implement prerequisite clocks
From: Alex Elder @ 2014-02-26 0:15 UTC (permalink / raw)
To: mturquette, mporter, bcm, galak, ijc+devicetree, mark.rutland,
pawel.moll, robh+dt
Cc: bcm-kernel-feedback-list, linux-arm-kernel, devicetree,
linux-kernel
In-Reply-To: <1393373752-30875-1-git-send-email-elder@linaro.org>
Allow a clock to specify a "prerequisite" clock. The prerequisite
clock must be initialized before the clock that depends on it. A
prerequisite clock is defined initially by its name; as that clock
gets initialized the name gets replaced with a pointer to its clock
structure pointer. In order to allow getting a reference to a clock
by its name we call clkdev_add() for each clock as it gets set up.
A new clk_lookup structure is added to the kona_clk type for this
purpose.
Rework the KONA_CLK() macro, and define a new KONA_CLK_PREREQ()
variant that allows a prerequisite clock to be specified.
There exist clocks that could specify more than one prequisite, but
almost all clocks only ever use one. We can add support for more
than one if we find we need it at some point.
Signed-off-by: Alex Elder <elder@linaro.org>
---
drivers/clk/bcm/clk-kona-setup.c | 16 ++++++++++----
drivers/clk/bcm/clk-kona.c | 45 ++++++++++++++++++++++++++++++++++++++
drivers/clk/bcm/clk-kona.h | 20 ++++++++++++++---
3 files changed, 74 insertions(+), 7 deletions(-)
diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c
index 757de19..973053b 100644
--- a/drivers/clk/bcm/clk-kona-setup.c
+++ b/drivers/clk/bcm/clk-kona-setup.c
@@ -685,6 +685,9 @@ peri_clk_setup(struct peri_clk_data *data, struct clk_init_data *init_data)
static void bcm_clk_teardown(struct kona_clk *bcm_clk)
{
+ /* There is no function defined for this (yet) */
+ /* clkdev_remove(&bcm_clk->cl); */
+
switch (bcm_clk->type) {
case bcm_clk_peri:
peri_clk_teardown(bcm_clk->data, &bcm_clk->init_data);
@@ -718,6 +721,7 @@ static void kona_clk_teardown(struct clk *clk)
struct clk *kona_clk_setup(struct kona_clk *bcm_clk)
{
struct clk_init_data *init_data = &bcm_clk->init_data;
+ const char *name = init_data->name;
struct clk *clk = NULL;
switch (bcm_clk->type) {
@@ -727,14 +731,13 @@ struct clk *kona_clk_setup(struct kona_clk *bcm_clk)
break;
default:
pr_err("%s: clock type %d invalid for %s\n", __func__,
- (int)bcm_clk->type, init_data->name);
+ (int)bcm_clk->type, name);
return NULL;
}
/* Make sure everything makes sense before we set it up */
if (!kona_clk_valid(bcm_clk)) {
- pr_err("%s: clock data invalid for %s\n", __func__,
- init_data->name);
+ pr_err("%s: clock data invalid for %s\n", __func__, name);
goto out_teardown;
}
@@ -742,11 +745,16 @@ struct clk *kona_clk_setup(struct kona_clk *bcm_clk)
clk = clk_register(NULL, &bcm_clk->hw);
if (IS_ERR(clk)) {
pr_err("%s: error registering clock %s (%ld)\n", __func__,
- init_data->name, PTR_ERR(clk));
+ name, PTR_ERR(clk));
goto out_teardown;
}
BUG_ON(!clk);
+ /* Make it so we can look the clock up using clk_find() */
+ bcm_clk->cl.con_id = name;
+ bcm_clk->cl.clk = clk;
+ clkdev_add(&bcm_clk->cl);
+
return clk;
out_teardown:
bcm_clk_teardown(bcm_clk);
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index 6caed3b..37f7861 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -1193,6 +1193,48 @@ static bool __peri_clk_init(struct kona_clk *bcm_clk)
return true;
}
+static bool __kona_clk_init(struct kona_clk *bcm_clk);
+static bool __kona_prereq_init(struct kona_clk *bcm_clk)
+{
+ struct clk *clk;
+ struct clk_hw *hw;
+ struct kona_clk *prereq;
+
+ BUG_ON(clk_is_initialized(bcm_clk));
+
+ if (!bcm_clk->prereq)
+ return true;
+
+ clk = clk_get(NULL, bcm_clk->prereq);
+ if (IS_ERR(clk)) {
+ pr_err("%s: unable to get prereq clock %s for %s\n",
+ __func__, bcm_clk->prereq, bcm_clk->init_data.name);
+ return false;
+ }
+ hw = __clk_get_hw(clk);
+ if (!hw) {
+ pr_err("%s: null hw pointer for clock %s\n", __func__,
+ bcm_clk->init_data.name);
+ return false;
+ }
+ prereq = to_kona_clk(hw);
+ if (prereq->ccu != bcm_clk->ccu) {
+ pr_err("%s: prereq clock %s CCU different for clock %s\n",
+ __func__, bcm_clk->prereq, bcm_clk->init_data.name);
+ return false;
+ }
+
+ /* Initialize the prerequisite clock first */
+ if (!__kona_clk_init(prereq)) {
+ pr_err("%s: failed to init prereq %s for clock %s\n",
+ __func__, bcm_clk->prereq, bcm_clk->init_data.name);
+ return false;
+ }
+ bcm_clk->prereq_clk = clk;
+
+ return true;
+}
+
static bool __kona_clk_init(struct kona_clk *bcm_clk)
{
bool ret = false;
@@ -1200,6 +1242,9 @@ static bool __kona_clk_init(struct kona_clk *bcm_clk)
if (clk_is_initialized(bcm_clk))
return true;
+ if (!__kona_prereq_init(bcm_clk))
+ return false;
+
switch (bcm_clk->type) {
case bcm_clk_peri:
ret = __peri_clk_init(bcm_clk);
diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h
index 01fa776..27e0913 100644
--- a/drivers/clk/bcm/clk-kona.h
+++ b/drivers/clk/bcm/clk-kona.h
@@ -22,6 +22,8 @@
#include <linux/device.h>
#include <linux/of.h>
#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/debugfs.h>
#define BILLION 1000000000
@@ -407,6 +409,11 @@ struct kona_clk {
struct ccu_data *ccu; /* ccu this clock is associated with */
enum bcm_clk_type type;
u32 flags; /* BCM_CLK_KONA_FLAGS_* below */
+ struct clk_lookup cl;
+ union {
+ const char *prereq;
+ struct clk *prereq_clk;
+ };
union {
void *data;
struct peri_clk_data *peri;
@@ -422,15 +429,22 @@ struct kona_clk {
#define BCM_CLK_KONA_FLAGS_INITIALIZED ((u32)1 << 0) /* Clock initialized */
/* Initialization macro for an entry in a CCU's kona_clks[] array. */
-#define KONA_CLK(_ccu_name, _clk_name, _type) \
- { \
+#define ___KONA_CLK_COMMON(_ccu_name, _clk_name, _type) \
.init_data = { \
.name = #_clk_name, \
.ops = &kona_ ## _type ## _clk_ops, \
}, \
.ccu = &_ccu_name ## _ccu_data, \
.type = bcm_clk_ ## _type, \
- .data = &_clk_name ## _data, \
+ .data = &_clk_name ## _data
+#define KONA_CLK_PREREQ(_ccu_name, _clk_name, _type, _prereq) \
+ { \
+ .prereq = #_prereq, \
+ ___KONA_CLK_COMMON(_ccu_name, _clk_name, _type), \
+ }
+#define KONA_CLK(_ccu_name, _clk_name, _type) \
+ { \
+ ___KONA_CLK_COMMON(_ccu_name, _clk_name, _type), \
}
#define LAST_KONA_CLK { .type = bcm_clk_none }
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 08/12] clk: bcm281xx: add an initialized flag
From: Alex Elder @ 2014-02-26 0:15 UTC (permalink / raw)
To: mturquette-QSEj5FYQhm4dnm+yROfE0A, mporter-QSEj5FYQhm4dnm+yROfE0A,
bcm-xK7y4jjYLqYh9ZMKESR00Q, galak-sgV2jX0FEOL9JmXXK+q4OQ,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg, mark.rutland-5wv7dgnIgG8,
pawel.moll-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1393373752-30875-1-git-send-email-elder-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Add a flag that tracks whether a clock has already been initialized.
This will be used by the next patch to avoid initializing a clock
more than once when it's listed as a prerequisite.
Signed-off-by: Alex Elder <elder-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
drivers/clk/bcm/clk-kona.c | 16 ++++++++++++++--
drivers/clk/bcm/clk-kona.h | 7 +++++++
2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index 64b6361..6caed3b 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -27,6 +27,9 @@
#define CCU_ACCESS_PASSWORD 0xA5A500
#define CLK_GATE_DELAY_LOOP 2000
+#define clk_is_initialized(_clk) FLAG_TEST((_clk), KONA, INITIALIZED)
+#define clk_set_initialized(_clk) FLAG_SET((_clk), KONA, INITIALIZED)
+
/* Bitfield operations */
/* Produces a mask of set bits covering a range of a 32-bit value */
@@ -1192,13 +1195,22 @@ static bool __peri_clk_init(struct kona_clk *bcm_clk)
static bool __kona_clk_init(struct kona_clk *bcm_clk)
{
+ bool ret = false;
+
+ if (clk_is_initialized(bcm_clk))
+ return true;
+
switch (bcm_clk->type) {
case bcm_clk_peri:
- return __peri_clk_init(bcm_clk);
+ ret = __peri_clk_init(bcm_clk);
+ break;
default:
BUG();
}
- return -EINVAL;
+ if (ret)
+ clk_set_initialized(bcm_clk);
+
+ return ret;
}
/* Set a CCU and all its clocks into their desired initial state */
diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h
index c6285d2..01fa776 100644
--- a/drivers/clk/bcm/clk-kona.h
+++ b/drivers/clk/bcm/clk-kona.h
@@ -406,6 +406,7 @@ struct kona_clk {
struct clk_init_data init_data; /* includes name of this clock */
struct ccu_data *ccu; /* ccu this clock is associated with */
enum bcm_clk_type type;
+ u32 flags; /* BCM_CLK_KONA_FLAGS_* below */
union {
void *data;
struct peri_clk_data *peri;
@@ -414,6 +415,12 @@ struct kona_clk {
#define to_kona_clk(_hw) \
container_of(_hw, struct kona_clk, hw)
+/*
+ * Kona clock flags:
+ * INITIALIZED clock has been initialized already
+ */
+#define BCM_CLK_KONA_FLAGS_INITIALIZED ((u32)1 << 0) /* Clock initialized */
+
/* Initialization macro for an entry in a CCU's kona_clks[] array. */
#define KONA_CLK(_ccu_name, _clk_name, _type) \
{ \
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 07/12] clk: bcm281xx: add clock hysteresis support
From: Alex Elder @ 2014-02-26 0:15 UTC (permalink / raw)
To: mturquette, mporter, bcm, galak, ijc+devicetree, mark.rutland,
pawel.moll, robh+dt
Cc: bcm-kernel-feedback-list, linux-arm-kernel, devicetree,
linux-kernel
In-Reply-To: <1393373752-30875-1-git-send-email-elder@linaro.org>
Add support for clock gate hysteresis control. For now, if it's
defined for a clock, it's enabled.
Signed-off-by: Alex Elder <elder@linaro.org>
---
drivers/clk/bcm/clk-kona-setup.c | 30 ++++++++++++++++++++++++++++++
drivers/clk/bcm/clk-kona.c | 33 +++++++++++++++++++++++++++++++++
drivers/clk/bcm/clk-kona.h | 19 +++++++++++++++++++
3 files changed, 82 insertions(+)
diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c
index 5a49deb..757de19 100644
--- a/drivers/clk/bcm/clk-kona-setup.c
+++ b/drivers/clk/bcm/clk-kona-setup.c
@@ -81,6 +81,7 @@ static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk)
struct peri_clk_data *peri;
struct bcm_clk_policy *policy;
struct bcm_clk_gate *gate;
+ struct bcm_clk_hyst *hyst;
struct bcm_clk_div *div;
struct bcm_clk_sel *sel;
struct bcm_clk_trig *trig;
@@ -106,12 +107,25 @@ static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk)
}
gate = &peri->gate;
+ hyst = &peri->hyst;
if (gate_exists(gate)) {
if (gate->offset > limit) {
pr_err("%s: bad gate offset for %s (%u > %u)\n",
__func__, name, gate->offset, limit);
return false;
}
+
+ if (hyst_exists(hyst)) {
+ if (hyst->offset > limit) {
+ pr_err("%s: bad hysteresis offset for %s "
+ "(%u > %u)\n", __func__,
+ name, hyst->offset, limit);
+ return false;
+ }
+ }
+ } else if (hyst_exists(hyst)) {
+ pr_err("%s: hysteresis but no gate for %s\n", __func__, name);
+ return false;
}
div = &peri->div;
@@ -261,6 +275,17 @@ static bool gate_valid(struct bcm_clk_gate *gate, const char *field_name,
return true;
}
+static bool hyst_valid(struct bcm_clk_hyst *hyst, const char *clock_name)
+{
+ if (!bit_posn_valid(hyst->en_bit, "hysteresis enable", clock_name))
+ return false;
+
+ if (!bit_posn_valid(hyst->val_bit, "hysteresis value", clock_name))
+ return false;
+
+ return true;
+}
+
/*
* A selector bitfield must be valid. Its parent_sel array must
* also be reasonable for the field.
@@ -378,6 +403,7 @@ peri_clk_data_valid(struct kona_clk *bcm_clk)
struct peri_clk_data *peri;
struct bcm_clk_policy *policy;
struct bcm_clk_gate *gate;
+ struct bcm_clk_hyst *hyst;
struct bcm_clk_sel *sel;
struct bcm_clk_div *div;
struct bcm_clk_div *pre_div;
@@ -405,6 +431,10 @@ peri_clk_data_valid(struct kona_clk *bcm_clk)
if (gate_exists(gate) && !gate_valid(gate, "gate", name))
return false;
+ hyst = &peri->hyst;
+ if (hyst_exists(hyst) && !hyst_valid(hyst, name))
+ return false;
+
sel = &peri->sel;
if (selector_exists(sel)) {
if (!sel_valid(sel, "selector", name))
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index bf9661c..64b6361 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -527,6 +527,35 @@ static int clk_gate(struct ccu_data *ccu, const char *name,
return -EIO;
}
+/* Hysteresis operations */
+
+/*
+ * If a clock gate requires a turn-off delay it will have
+ * "hysteresis" register bits defined. The first, if set, enables
+ * the delay; and if enabled, the second bit determines whether the
+ * delay is "low" or "high" (1 means high). For now, if it's
+ * defined for a clock, we set it.
+ */
+static bool hyst_init(struct ccu_data *ccu, struct bcm_clk_hyst *hyst)
+{
+ u32 offset;
+ u32 reg_val;
+ u32 mask;
+
+ if (!hyst_exists(hyst))
+ return true;
+
+ offset = hyst->offset;
+ mask = (u32)1 << hyst->en_bit;
+ mask |= (u32)1 << hyst->val_bit;
+
+ reg_val = __ccu_read(ccu, offset);
+ reg_val |= mask;
+ __ccu_write(ccu, offset, reg_val);
+
+ return true;
+}
+
/* Trigger operations */
/*
@@ -1129,6 +1158,10 @@ static bool __peri_clk_init(struct kona_clk *bcm_clk)
pr_err("%s: error initializing gate for %s\n", __func__, name);
return false;
}
+ if (!hyst_init(ccu, &peri->hyst)) {
+ pr_err("%s: error initializing hyst for %s\n", __func__, name);
+ return false;
+ }
if (!div_init(ccu, &peri->gate, &peri->div, &peri->trig)) {
pr_err("%s: error initializing divider for %s\n", __func__,
name);
diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h
index c390ca4..c6285d2 100644
--- a/drivers/clk/bcm/clk-kona.h
+++ b/drivers/clk/bcm/clk-kona.h
@@ -60,6 +60,8 @@
#define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED)
+#define hyst_exists(hyst) ((hyst)->offset != 0)
+
#define divider_exists(div) FLAG_TEST(div, DIV, EXISTS)
#define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED)
#define divider_has_fraction(div) (!divider_is_fixed(div) && \
@@ -205,6 +207,22 @@ struct bcm_clk_gate {
.flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \
}
+/* Gate hysteresis for clocks */
+struct bcm_clk_hyst {
+ u32 offset; /* hyst register offset (normally CLKGATE) */
+ u32 en_bit; /* bit used to enable hysteresis */
+ u32 val_bit; /* if enabled: 0 = low delay; 1 = high delay */
+};
+
+/* Hysteresis initialization macro */
+
+#define HYST(_offset, _en_bit, _val_bit) \
+ { \
+ .offset = (_offset), \
+ .en_bit = (_en_bit), \
+ .val_bit = (_val_bit), \
+ }
+
/*
* Each clock can have zero, one, or two dividers which change the
* output rate of the clock. Each divider can be either fixed or
@@ -372,6 +390,7 @@ struct bcm_clk_trig {
struct peri_clk_data {
struct bcm_clk_policy policy;
struct bcm_clk_gate gate;
+ struct bcm_clk_hyst hyst;
struct bcm_clk_trig pre_trig;
struct bcm_clk_div pre_div;
struct bcm_clk_trig trig;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 06/12] clk: bcm281xx: add clock policy support
From: Alex Elder @ 2014-02-26 0:15 UTC (permalink / raw)
To: mturquette, mporter, bcm, galak, ijc+devicetree, mark.rutland,
pawel.moll, robh+dt
Cc: bcm-kernel-feedback-list, linux-arm-kernel, devicetree,
linux-kernel
In-Reply-To: <1393373752-30875-1-git-send-email-elder@linaro.org>
Add support for CCU policy engine control, and also for setting the
mask bits for bus clocks that require a policy change to get
activated. This includes adding validity checking framework for
CCUs, to validate the policy fields if defined.
Signed-off-by: Alex Elder <elder@linaro.org>
---
drivers/clk/bcm/clk-kona-setup.c | 92 ++++++++++++++++++++++
drivers/clk/bcm/clk-kona.c | 155 ++++++++++++++++++++++++++++++++++++++
drivers/clk/bcm/clk-kona.h | 71 +++++++++++++++++
3 files changed, 318 insertions(+)
diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c
index 196922b..5a49deb 100644
--- a/drivers/clk/bcm/clk-kona-setup.c
+++ b/drivers/clk/bcm/clk-kona-setup.c
@@ -25,6 +25,31 @@ LIST_HEAD(ccu_list); /* The list of set up CCUs */
/* Validity checking */
+static bool ccu_data_offsets_valid(struct ccu_data *ccu)
+{
+ struct ccu_policy *ccu_policy = &ccu->policy;
+ u32 limit;
+
+ limit = ccu->range - sizeof(u32);
+ limit = round_down(limit, sizeof(u32));
+ if (ccu_policy_exists(ccu_policy)) {
+ if (ccu_policy->enable.offset > limit) {
+ pr_err("%s: bad policy enable offset for %s "
+ "(%u > %u)\n", __func__,
+ ccu->name, ccu_policy->enable.offset, limit);
+ return false;
+ }
+ if (ccu_policy->control.offset > limit) {
+ pr_err("%s: bad policy control offset for %s "
+ "(%u > %u)\n", __func__,
+ ccu->name, ccu_policy->control.offset, limit);
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool clk_requires_trigger(struct kona_clk *bcm_clk)
{
struct peri_clk_data *peri = bcm_clk->peri;
@@ -54,6 +79,7 @@ static bool clk_requires_trigger(struct kona_clk *bcm_clk)
static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk)
{
struct peri_clk_data *peri;
+ struct bcm_clk_policy *policy;
struct bcm_clk_gate *gate;
struct bcm_clk_div *div;
struct bcm_clk_sel *sel;
@@ -70,6 +96,15 @@ static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk)
limit = range - sizeof(u32);
limit = round_down(limit, sizeof(u32));
+ policy = &peri->policy;
+ if (policy_exists(policy)) {
+ if (policy->offset > limit) {
+ pr_err("%s: bad policy offset for %s (%u > %u)\n",
+ __func__, name, policy->offset, limit);
+ return false;
+ }
+ }
+
gate = &peri->gate;
if (gate_exists(gate)) {
if (gate->offset > limit) {
@@ -167,6 +202,36 @@ static bool bitfield_valid(u32 shift, u32 width, const char *field_name,
return true;
}
+static bool
+ccu_policy_valid(struct ccu_policy *ccu_policy, const char *ccu_name)
+{
+ struct bcm_lvm_en *enable = &ccu_policy->enable;
+ struct bcm_policy_ctl *control;
+
+ if (!bit_posn_valid(enable->bit, "policy enable", ccu_name))
+ return false;
+
+ control = &ccu_policy->control;
+ if (!bit_posn_valid(control->go_bit, "policy control GO", ccu_name))
+ return false;
+
+ if (!bit_posn_valid(control->atl_bit, "policy control ATL", ccu_name))
+ return false;
+
+ if (!bit_posn_valid(control->ac_bit, "policy control AC", ccu_name))
+ return false;
+
+ return true;
+}
+
+static bool policy_valid(struct bcm_clk_policy *policy, const char *clock_name)
+{
+ if (!bit_posn_valid(policy->bit, "policy", clock_name))
+ return false;
+
+ return true;
+}
+
/*
* All gates, if defined, have a status bit, and for hardware-only
* gates, that's it. Gates that can be software controlled also
@@ -311,6 +376,7 @@ static bool
peri_clk_data_valid(struct kona_clk *bcm_clk)
{
struct peri_clk_data *peri;
+ struct bcm_clk_policy *policy;
struct bcm_clk_gate *gate;
struct bcm_clk_sel *sel;
struct bcm_clk_div *div;
@@ -330,6 +396,11 @@ peri_clk_data_valid(struct kona_clk *bcm_clk)
peri = bcm_clk->peri;
name = bcm_clk->init_data.name;
+
+ policy = &peri->policy;
+ if (policy_exists(policy) && !policy_valid(policy, name))
+ return false;
+
gate = &peri->gate;
if (gate_exists(gate) && !gate_valid(gate, "gate", name))
return false;
@@ -678,6 +749,21 @@ static void kona_ccu_teardown(struct ccu_data *ccu)
ccu->base = NULL;
}
+static bool ccu_data_valid(struct ccu_data *ccu)
+{
+ struct ccu_policy *ccu_policy;
+
+ if (!ccu_data_offsets_valid(ccu))
+ return false;
+
+ ccu_policy = &ccu->policy;
+ if (ccu_policy_exists(ccu_policy))
+ if (!ccu_policy_valid(ccu_policy, ccu->name))
+ return false;
+
+ return true;
+}
+
/*
* Set up a CCU. Call the provided ccu_clks_setup callback to
* initialize the array of clocks provided by the CCU.
@@ -717,6 +803,12 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu,
}
ccu->range = (u32)range;
+
+ if (!ccu_data_valid(ccu)) {
+ pr_err("%s: ccu data not valid for %s\n", __func__, node->name);
+ goto out_err;
+ }
+
ccu->base = ioremap(res.start, ccu->range);
if (!ccu->base) {
pr_err("%s: unable to map CCU registers for %s\n", __func__,
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index 5c0dc5b..bf9661c 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -16,6 +16,14 @@
#include <linux/delay.h>
+/*
+ * "Policies" affect the frequencies of bus clocks provided by a
+ * CCU. (I believe these polices are named "Deep Sleep", "Economy",
+ * "Normal", and "Turbo".) A lower policy number has lower power
+ * consumption, and policy 2 is the default.
+ */
+#define CCU_POLICY_COUNT 4
+
#define CCU_ACCESS_PASSWORD 0xA5A500
#define CLK_GATE_DELAY_LOOP 2000
@@ -213,6 +221,148 @@ __ccu_wait_bit(struct ccu_data *ccu, u32 reg_offset, u32 bit, bool want)
return false;
}
+/* Policy operations */
+
+static bool __ccu_policy_engine_start(struct ccu_data *ccu, bool sync)
+{
+ struct bcm_policy_ctl *control = &ccu->policy.control;
+ u32 offset;
+ u32 go_bit;
+ u32 mask;
+ bool ret;
+
+ /* If we don't need to control policy for this CCU, we're done. */
+ if (!policy_ctl_exists(control))
+ return true;
+
+ offset = control->offset;
+ go_bit = control->go_bit;
+
+ /* Ensure we're not busy before we start */
+ ret = __ccu_wait_bit(ccu, offset, go_bit, false);
+ if (!ret) {
+ pr_err("%s: ccu %s policy engine wouldn't go idle\n",
+ __func__, ccu->name);
+ return false;
+ }
+
+ /*
+ * If it's a synchronous request, we'll wait for the voltage
+ * and frequency of the active load to stabilize before
+ * returning. To do this we select the active load by
+ * setting the ATL bit.
+ *
+ * An asynchronous request instead ramps the voltage in the
+ * background, and when that process stabilizes, the target
+ * load is copied to the active load and the CCU frequency
+ * is switched. We do this by selecting the target load
+ * (ATL bit clear) and setting the request auto-copy (AC bit
+ * set).
+ *
+ * Note, we do NOT read-modify-write this register.
+ */
+ mask = (u32)1 << go_bit;
+ if (sync)
+ mask |= 1 << control->atl_bit;
+ else
+ mask |= 1 << control->ac_bit;
+ __ccu_write(ccu, offset, mask);
+
+ /* Wait for indication that operation is complete. */
+ ret = __ccu_wait_bit(ccu, offset, go_bit, false);
+ if (!ret)
+ pr_err("%s: ccu %s policy engine never started\n",
+ __func__, ccu->name);
+
+ return ret;
+}
+
+static bool __ccu_policy_engine_stop(struct ccu_data *ccu)
+{
+ struct bcm_lvm_en *enable = &ccu->policy.enable;
+ u32 offset;
+ u32 enable_bit;
+ bool ret;
+
+ /* If we don't need to control policy for this CCU, we're done. */
+ if (!policy_lvm_en_exists(enable))
+ return true;
+
+ /* Ensure we're not busy before we start */
+ offset = enable->offset;
+ enable_bit = enable->bit;
+ ret = __ccu_wait_bit(ccu, offset, enable_bit, false);
+ if (!ret) {
+ pr_err("%s: ccu %s policy engine already stopped\n",
+ __func__, ccu->name);
+ return false;
+ }
+
+ /* Now set the bit to stop the engine (NO read-modify-write) */
+ __ccu_write(ccu, offset, (u32)1 << enable_bit);
+
+ /* Wait for indication that it has stopped. */
+ ret = __ccu_wait_bit(ccu, offset, enable_bit, false);
+ if (!ret)
+ pr_err("%s: ccu %s policy engine never stopped\n",
+ __func__, ccu->name);
+
+ return ret;
+}
+
+/*
+ * A CCU has four operating conditions ("policies"), and some clocks
+ * can be disabled or enabled based on which policy is currently in
+ * effect. Such clocks have a bit in a "policy mask" register for
+ * each policy indicating whether the clock is enabled for that
+ * policy or not. The bit position for a clock is the same for all
+ * four registers, and the 32-bit registers are at consecutive
+ * addresses.
+ */
+static bool policy_init(struct ccu_data *ccu, struct bcm_clk_policy *policy)
+{
+ u32 offset;
+ u32 mask;
+ int i;
+ bool ret;
+
+ if (!policy_exists(policy))
+ return true;
+
+ /*
+ * We need to stop the CCU policy engine to allow update
+ * of our policy bits.
+ */
+ if (!__ccu_policy_engine_stop(ccu)) {
+ pr_err("%s: unable to stop CCU %s policy engine\n",
+ __func__, ccu->name);
+ return false;
+ }
+
+ /*
+ * For now, if a clock defines its policy bit we just mark
+ * it "enabled" for all four policies.
+ */
+ offset = policy->offset;
+ mask = (u32)1 << policy->bit;
+ for (i = 0; i < CCU_POLICY_COUNT; i++) {
+ u32 reg_val;
+
+ reg_val = __ccu_read(ccu, offset);
+ reg_val |= mask;
+ __ccu_write(ccu, offset, reg_val);
+ offset += sizeof(u32);
+ }
+
+ /* We're done updating; fire up the policy engine again. */
+ ret = __ccu_policy_engine_start(ccu, true);
+ if (!ret)
+ pr_err("%s: unable to restart CCU %s policy engine\n",
+ __func__, ccu->name);
+
+ return ret;
+}
+
/* Gate operations */
/* Determine whether a clock is gated. CCU lock must be held. */
@@ -970,6 +1120,11 @@ static bool __peri_clk_init(struct kona_clk *bcm_clk)
BUG_ON(bcm_clk->type != bcm_clk_peri);
+ if (!policy_init(ccu, &peri->policy)) {
+ pr_err("%s: error initializing policy for %s\n",
+ __func__, name);
+ return false;
+ }
if (!gate_init(ccu, &peri->gate)) {
pr_err("%s: error initializing gate for %s\n", __func__, name);
return false;
diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h
index fba2740..c390ca4 100644
--- a/drivers/clk/bcm/clk-kona.h
+++ b/drivers/clk/bcm/clk-kona.h
@@ -43,8 +43,14 @@
#define FLAG_FLIP(obj, type, flag) ((obj)->flags ^= FLAG(type, flag))
#define FLAG_TEST(obj, type, flag) (!!((obj)->flags & FLAG(type, flag)))
+/* CCU field state tests */
+
+#define ccu_policy_exists(ccu_policy) ((ccu_policy)->enable.offset != 0)
+
/* Clock field state tests */
+#define policy_exists(policy) ((policy)->offset != 0)
+
#define gate_exists(gate) FLAG_TEST(gate, GATE, EXISTS)
#define gate_is_enabled(gate) FLAG_TEST(gate, GATE, ENABLED)
#define gate_is_hw_controllable(gate) FLAG_TEST(gate, GATE, HW)
@@ -62,6 +68,9 @@
#define selector_exists(sel) ((sel)->width != 0)
#define trigger_exists(trig) FLAG_TEST(trig, TRIG, EXISTS)
+#define policy_lvm_en_exists(enable) ((enable)->offset != 0)
+#define policy_ctl_exists(control) ((control)->offset != 0)
+
/* Clock type, used to tell common block what it's part of */
enum bcm_clk_type {
bcm_clk_none, /* undefined clock type */
@@ -71,6 +80,27 @@ enum bcm_clk_type {
};
/*
+ * CCU policy control for clocks. Clocks can be enabled or disabled
+ * based on the CCU policy in effect. One bit in each policy mask
+ * register (one per CCU policy) represents whether the clock is
+ * enabled when that policy is effect or not. The CCU policy engine
+ * must be stopped to update these bits, and must be restarted again
+ * afterward.
+ */
+struct bcm_clk_policy {
+ u32 offset; /* first policy mask register offset */
+ u32 bit; /* bit used in all mask registers */
+};
+
+/* Policy initialization macro */
+
+#define POLICY(_offset, _bit) \
+ { \
+ .offset = (_offset), \
+ .bit = (_bit), \
+ }
+
+/*
* Gating control and status is managed by a 32-bit gate register.
*
* There are several types of gating available:
@@ -340,6 +370,7 @@ struct bcm_clk_trig {
}
struct peri_clk_data {
+ struct bcm_clk_policy policy;
struct bcm_clk_gate gate;
struct bcm_clk_trig pre_trig;
struct bcm_clk_div pre_div;
@@ -378,6 +409,45 @@ struct kona_clk {
#define LAST_KONA_CLK { .type = bcm_clk_none }
/*
+ * CCU policy control. To enable software update of the policy
+ * tables the CCU policy engine must be stopped by setting the
+ * software update enable bit (LVM_EN). After an update the engine
+ * is restarted using the GO bit and either the GO_ATL or GO_AC bit.
+ */
+struct bcm_lvm_en {
+ u32 offset; /* LVM_EN register offset */
+ u32 bit; /* POLICY_CONFIG_EN bit in register */
+};
+
+/* Policy enable initialization macro */
+#define CCU_LVM_EN(_offset, _bit) \
+ { \
+ .offset = (_offset), \
+ .bit = (_bit), \
+ }
+
+struct bcm_policy_ctl {
+ u32 offset; /* POLICY_CTL register offset */
+ u32 go_bit;
+ u32 atl_bit; /* GO, GO_ATL, and GO_AC bits */
+ u32 ac_bit;
+};
+
+/* Policy control initialization macro */
+#define CCU_POLICY_CTL(_offset, _go_bit, _ac_bit, _atl_bit) \
+ { \
+ .offset = (_offset), \
+ .go_bit = (_go_bit), \
+ .ac_bit = (_ac_bit), \
+ .atl_bit = (_atl_bit), \
+ }
+
+struct ccu_policy {
+ struct bcm_lvm_en enable;
+ struct bcm_policy_ctl control;
+};
+
+/*
* Each CCU defines a mapped area of memory containing registers
* used to manage clocks implemented by the CCU. Access to memory
* within the CCU's space is serialized by a spinlock. Before any
@@ -390,6 +460,7 @@ struct ccu_data {
void __iomem *base; /* base of mapped address space */
spinlock_t lock; /* serialization lock */
bool write_enabled; /* write access is currently enabled */
+ struct ccu_policy policy;
struct list_head links; /* for ccu_list */
struct device_node *node;
struct clk_onecell_data clk_data;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 05/12] clk: bcm281xx: define CCU clock data statically
From: Alex Elder @ 2014-02-26 0:15 UTC (permalink / raw)
To: mturquette, mporter, bcm, galak, ijc+devicetree, mark.rutland,
pawel.moll, robh+dt
Cc: devicetree, bcm-kernel-feedback-list, linux-kernel,
linux-arm-kernel
In-Reply-To: <1393373752-30875-1-git-send-email-elder@linaro.org>
Rather than "manually" setting up each CCU's clock entries at run
time, define a flexible array of generic Kona clock structures
within the CCU structure itself. Each of these entries contains
generic kona clock information (like its CCU pointer and clock
framework initialization data). Each also has a pointer to a
structure contianing clock type-dependent initialization data
(like register definitions).
Since we'll iterate over these arrays we need to be sure they have
slots for all potential clock index values. (E.g. for the root CCU
we must have at least BCM281XX_ROOT_CCU_CLOCK_COUNT slots.) To
ensure this we always define an extra entry and fill it using the
special initializer LAST_KONA_CLK.
Just about everything we need to know about a clock can be defined
statically. As a result, kona_clk_setup() can be changed to take
just a kona_clk structure as its argument, and peri_clk_setup() can
be simplified. With the information pre-defined we are also able
to handle most clock setup genericially. We can do away with the
CCU-specific callback functions that previously were needed to set
up the entries in CCU's clock array.
Move the definition of the ccu_data structure down in "clk-kona.h"
to avoid a forward dependency.
Signed-off-by: Alex Elder <elder@linaro.org>
---
drivers/clk/bcm/clk-bcm281xx.c | 132 ++++++++++++++++++--------------------
drivers/clk/bcm/clk-kona-setup.c | 60 ++++++++---------
drivers/clk/bcm/clk-kona.h | 86 +++++++++++++------------
3 files changed, 134 insertions(+), 144 deletions(-)
diff --git a/drivers/clk/bcm/clk-bcm281xx.c b/drivers/clk/bcm/clk-bcm281xx.c
index d72f2ae..71a65a4 100644
--- a/drivers/clk/bcm/clk-bcm281xx.c
+++ b/drivers/clk/bcm/clk-bcm281xx.c
@@ -41,6 +41,11 @@ static struct peri_clk_data frac_1m_data = {
static struct ccu_data root_ccu_data = {
BCM281XX_CCU_COMMON(root, ROOT),
+ .kona_clks = {
+ [BCM281XX_ROOT_CCU_FRAC_1M] =
+ KONA_CLK(root, frac_1m, peri),
+ [BCM281XX_ROOT_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
};
/* AON CCU */
@@ -74,6 +79,15 @@ static struct peri_clk_data pmu_bsc_var_data = {
static struct ccu_data aon_ccu_data = {
BCM281XX_CCU_COMMON(aon, AON),
+ .kona_clks = {
+ [BCM281XX_AON_CCU_HUB_TIMER] =
+ KONA_CLK(aon, hub_timer, peri),
+ [BCM281XX_AON_CCU_PMU_BSC] =
+ KONA_CLK(aon, pmu_bsc, peri),
+ [BCM281XX_AON_CCU_PMU_BSC_VAR] =
+ KONA_CLK(aon, pmu_bsc_var, peri),
+ [BCM281XX_AON_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
};
/* Hub CCU */
@@ -88,6 +102,11 @@ static struct peri_clk_data tmon_1m_data = {
static struct ccu_data hub_ccu_data = {
BCM281XX_CCU_COMMON(hub, HUB),
+ .kona_clks = {
+ [BCM281XX_HUB_CCU_TMON_1M] =
+ KONA_CLK(hub, tmon_1m, peri),
+ [BCM281XX_HUB_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
};
/* Master CCU */
@@ -175,6 +194,23 @@ static struct peri_clk_data hsic2_12m_data = {
static struct ccu_data master_ccu_data = {
BCM281XX_CCU_COMMON(master, MASTER),
+ .kona_clks = {
+ [BCM281XX_MASTER_CCU_SDIO1] =
+ KONA_CLK(master, sdio1, peri),
+ [BCM281XX_MASTER_CCU_SDIO2] =
+ KONA_CLK(master, sdio2, peri),
+ [BCM281XX_MASTER_CCU_SDIO3] =
+ KONA_CLK(master, sdio3, peri),
+ [BCM281XX_MASTER_CCU_SDIO4] =
+ KONA_CLK(master, sdio4, peri),
+ [BCM281XX_MASTER_CCU_USB_IC] =
+ KONA_CLK(master, usb_ic, peri),
+ [BCM281XX_MASTER_CCU_HSIC2_48M] =
+ KONA_CLK(master, hsic2_48m, peri),
+ [BCM281XX_MASTER_CCU_HSIC2_12M] =
+ KONA_CLK(master, hsic2_12m, peri),
+ [BCM281XX_MASTER_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
};
/* Slave CCU */
@@ -287,96 +323,56 @@ static struct peri_clk_data pwm_data = {
static struct ccu_data slave_ccu_data = {
BCM281XX_CCU_COMMON(slave, SLAVE),
+ .kona_clks = {
+ [BCM281XX_SLAVE_CCU_UARTB] =
+ KONA_CLK(slave, uartb, peri),
+ [BCM281XX_SLAVE_CCU_UARTB2] =
+ KONA_CLK(slave, uartb2, peri),
+ [BCM281XX_SLAVE_CCU_UARTB3] =
+ KONA_CLK(slave, uartb3, peri),
+ [BCM281XX_SLAVE_CCU_UARTB4] =
+ KONA_CLK(slave, uartb4, peri),
+ [BCM281XX_SLAVE_CCU_SSP0] =
+ KONA_CLK(slave, ssp0, peri),
+ [BCM281XX_SLAVE_CCU_SSP2] =
+ KONA_CLK(slave, ssp2, peri),
+ [BCM281XX_SLAVE_CCU_BSC1] =
+ KONA_CLK(slave, bsc1, peri),
+ [BCM281XX_SLAVE_CCU_BSC2] =
+ KONA_CLK(slave, bsc2, peri),
+ [BCM281XX_SLAVE_CCU_BSC3] =
+ KONA_CLK(slave, bsc3, peri),
+ [BCM281XX_SLAVE_CCU_PWM] =
+ KONA_CLK(slave, pwm, peri),
+ [BCM281XX_SLAVE_CCU_CLOCK_COUNT] = LAST_KONA_CLK,
+ },
};
-/*
- * CCU setup routines
- *
- * These are called from kona_dt_ccu_setup() to initialize the array
- * of clocks provided by the CCU. Once allocated, the entries in
- * the array are initialized by calling kona_clk_setup() with the
- * initialization data for each clock. They return 0 if successful
- * or an error code otherwise.
- */
-static int __init bcm281xx_root_ccu_clks_setup(struct ccu_data *ccu)
-{
- PERI_CLK_SETUP(ccu, BCM281XX_ROOT_CCU_FRAC_1M, frac_1m);
-
- return 0;
-}
-
-static int __init bcm281xx_aon_ccu_clks_setup(struct ccu_data *ccu)
-{
- PERI_CLK_SETUP(ccu, BCM281XX_AON_CCU_HUB_TIMER, hub_timer);
- PERI_CLK_SETUP(ccu, BCM281XX_AON_CCU_PMU_BSC, pmu_bsc);
- PERI_CLK_SETUP(ccu, BCM281XX_AON_CCU_PMU_BSC_VAR, pmu_bsc_var);
-
- return 0;
-}
-
-static int __init bcm281xx_hub_ccu_clks_setup(struct ccu_data *ccu)
-{
- PERI_CLK_SETUP(ccu, BCM281XX_HUB_CCU_TMON_1M, tmon_1m);
-
- return 0;
-}
-
-static int __init bcm281xx_master_ccu_clks_setup(struct ccu_data *ccu)
-{
- PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_SDIO1, sdio1);
- PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_SDIO2, sdio2);
- PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_SDIO3, sdio3);
- PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_SDIO4, sdio4);
- PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_USB_IC, usb_ic);
- PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_HSIC2_48M, hsic2_48m);
- PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_HSIC2_12M, hsic2_12m);
-
- return 0;
-}
-
-static int __init bcm281xx_slave_ccu_clks_setup(struct ccu_data *ccu)
-{
- PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_UARTB, uartb);
- PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_UARTB2, uartb2);
- PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_UARTB3, uartb3);
- PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_UARTB4, uartb4);
- PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_SSP0, ssp0);
- PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_SSP2, ssp2);
- PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_BSC1, bsc1);
- PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_BSC2, bsc2);
- PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_BSC3, bsc3);
- PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_PWM, pwm);
-
- return 0;
-}
-
/* Device tree match table callback functions */
static void __init kona_dt_root_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(&root_ccu_data, node, bcm281xx_root_ccu_clks_setup);
+ kona_dt_ccu_setup(&root_ccu_data, node);
}
static void __init kona_dt_aon_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(&aon_ccu_data, node, bcm281xx_aon_ccu_clks_setup);
+ kona_dt_ccu_setup(&aon_ccu_data, node);
}
static void __init kona_dt_hub_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(&hub_ccu_data, node, bcm281xx_hub_ccu_clks_setup);
+ kona_dt_ccu_setup(&hub_ccu_data, node);
}
static void __init kona_dt_master_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(&master_ccu_data, node,
- bcm281xx_master_ccu_clks_setup);
+ kona_dt_ccu_setup(&master_ccu_data, node);
}
static void __init kona_dt_slave_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(&slave_ccu_data, node,
- bcm281xx_slave_ccu_clks_setup);
+ kona_dt_ccu_setup(&slave_ccu_data, node);
}
CLK_OF_DECLARE(bcm281xx_root_ccu, BCM281XX_DT_ROOT_CCU_COMPAT,
diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c
index 4468065..196922b 100644
--- a/drivers/clk/bcm/clk-kona-setup.c
+++ b/drivers/clk/bcm/clk-kona-setup.c
@@ -566,7 +566,6 @@ static void peri_clk_teardown(struct peri_clk_data *data,
struct clk_init_data *init_data)
{
clk_sel_teardown(&data->sel, init_data);
- init_data->ops = NULL;
}
/*
@@ -575,10 +574,9 @@ static void peri_clk_teardown(struct peri_clk_data *data,
* that can be assigned if the clock has one or more parent clocks
* associated with it.
*/
-static int peri_clk_setup(struct ccu_data *ccu, struct peri_clk_data *data,
- struct clk_init_data *init_data)
+static int
+peri_clk_setup(struct peri_clk_data *data, struct clk_init_data *init_data)
{
- init_data->ops = &kona_peri_clk_ops;
init_data->flags = CLK_IGNORE_UNUSED;
return clk_sel_setup(data->clocks, &data->sel, init_data);
@@ -616,39 +614,26 @@ static void kona_clk_teardown(struct clk *clk)
bcm_clk_teardown(bcm_clk);
}
-struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
- enum bcm_clk_type type, void *data)
+struct clk *kona_clk_setup(struct kona_clk *bcm_clk)
{
- struct kona_clk *bcm_clk;
- struct clk_init_data *init_data;
+ struct clk_init_data *init_data = &bcm_clk->init_data;
struct clk *clk = NULL;
- bcm_clk = kzalloc(sizeof(*bcm_clk), GFP_KERNEL);
- if (!bcm_clk) {
- pr_err("%s: failed to allocate bcm_clk for %s\n", __func__,
- name);
- return NULL;
- }
- bcm_clk->ccu = ccu;
- bcm_clk->init_data.name = name;
-
- init_data = &bcm_clk->init_data;
- init_data->name = name;
- switch (type) {
+ switch (bcm_clk->type) {
case bcm_clk_peri:
- if (peri_clk_setup(ccu, data, init_data))
- goto out_free;
+ if (peri_clk_setup(bcm_clk->data, init_data))
+ return NULL;
break;
default:
- data = NULL;
- break;
+ pr_err("%s: clock type %d invalid for %s\n", __func__,
+ (int)bcm_clk->type, init_data->name);
+ return NULL;
}
- bcm_clk->type = type;
- bcm_clk->data = data;
/* Make sure everything makes sense before we set it up */
if (!kona_clk_valid(bcm_clk)) {
- pr_err("%s: clock data invalid for %s\n", __func__, name);
+ pr_err("%s: clock data invalid for %s\n", __func__,
+ init_data->name);
goto out_teardown;
}
@@ -656,7 +641,7 @@ struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
clk = clk_register(NULL, &bcm_clk->hw);
if (IS_ERR(clk)) {
pr_err("%s: error registering clock %s (%ld)\n", __func__,
- name, PTR_ERR(clk));
+ init_data->name, PTR_ERR(clk));
goto out_teardown;
}
BUG_ON(!clk);
@@ -664,8 +649,6 @@ struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
return clk;
out_teardown:
bcm_clk_teardown(bcm_clk);
-out_free:
- kfree(bcm_clk);
return NULL;
}
@@ -700,11 +683,11 @@ static void kona_ccu_teardown(struct ccu_data *ccu)
* initialize the array of clocks provided by the CCU.
*/
void __init kona_dt_ccu_setup(struct ccu_data *ccu,
- struct device_node *node,
- int (*ccu_clks_setup)(struct ccu_data *))
+ struct device_node *node)
{
struct resource res = { 0 };
resource_size_t range;
+ unsigned int i;
int ret;
if (ccu->clk_data.clk_num) {
@@ -743,9 +726,16 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu,
ccu->node = of_node_get(node);
list_add_tail(&ccu->links, &ccu_list);
- /* Set up clocks array (in ccu->clk_data) */
- if (ccu_clks_setup(ccu))
- goto out_err;
+ /*
+ * Set up each defined kona clock and save the result in
+ * the clock framework clock array (in ccu->data). Then
+ * register as a provider for these clocks.
+ */
+ for (i = 0; i < ccu->clk_data.clk_num; i++) {
+ if (!ccu->kona_clks[i].ccu)
+ continue;
+ ccu->clk_data.clks[i] = kona_clk_setup(&ccu->kona_clks[i]);
+ }
ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->clk_data);
if (ret) {
diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h
index 0748c9b..fba2740 100644
--- a/drivers/clk/bcm/clk-kona.h
+++ b/drivers/clk/bcm/clk-kona.h
@@ -71,35 +71,6 @@ enum bcm_clk_type {
};
/*
- * Each CCU defines a mapped area of memory containing registers
- * used to manage clocks implemented by the CCU. Access to memory
- * within the CCU's space is serialized by a spinlock. Before any
- * (other) address can be written, a special access "password" value
- * must be written to its WR_ACCESS register (located at the base
- * address of the range). We keep track of the name of each CCU as
- * it is set up, and maintain them in a list.
- */
-struct ccu_data {
- void __iomem *base; /* base of mapped address space */
- spinlock_t lock; /* serialization lock */
- bool write_enabled; /* write access is currently enabled */
- struct list_head links; /* for ccu_list */
- struct device_node *node;
- struct clk_onecell_data clk_data;
- const char *name;
- u32 range; /* byte range of address space */
-};
-
-/* Initialization for common fields in a Kona ccu_data structure */
-#define KONA_CCU_COMMON(_prefix, _name, _ucase_name) \
- .name = #_name "_ccu", \
- .lock = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock), \
- .links = LIST_HEAD_INIT(_name ## _ccu_data.links), \
- .clk_data = { \
- .clk_num = _prefix ## _ ## _ucase_name ## _CCU_CLOCK_COUNT, \
- }
-
-/*
* Gating control and status is managed by a 32-bit gate register.
*
* There are several types of gating available:
@@ -393,18 +364,53 @@ struct kona_clk {
#define to_kona_clk(_hw) \
container_of(_hw, struct kona_clk, hw)
+/* Initialization macro for an entry in a CCU's kona_clks[] array. */
+#define KONA_CLK(_ccu_name, _clk_name, _type) \
+ { \
+ .init_data = { \
+ .name = #_clk_name, \
+ .ops = &kona_ ## _type ## _clk_ops, \
+ }, \
+ .ccu = &_ccu_name ## _ccu_data, \
+ .type = bcm_clk_ ## _type, \
+ .data = &_clk_name ## _data, \
+ }
+#define LAST_KONA_CLK { .type = bcm_clk_none }
+
+/*
+ * Each CCU defines a mapped area of memory containing registers
+ * used to manage clocks implemented by the CCU. Access to memory
+ * within the CCU's space is serialized by a spinlock. Before any
+ * (other) address can be written, a special access "password" value
+ * must be written to its WR_ACCESS register (located at the base
+ * address of the range). We keep track of the name of each CCU as
+ * it is set up, and maintain them in a list.
+ */
+struct ccu_data {
+ void __iomem *base; /* base of mapped address space */
+ spinlock_t lock; /* serialization lock */
+ bool write_enabled; /* write access is currently enabled */
+ struct list_head links; /* for ccu_list */
+ struct device_node *node;
+ struct clk_onecell_data clk_data;
+ const char *name;
+ u32 range; /* byte range of address space */
+ struct kona_clk kona_clks[]; /* must be last */
+};
+
+/* Initialization for common fields in a Kona ccu_data structure */
+#define KONA_CCU_COMMON(_prefix, _name, _ccuname) \
+ .name = #_name "_ccu", \
+ .lock = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock), \
+ .links = LIST_HEAD_INIT(_name ## _ccu_data.links), \
+ .clk_data = { \
+ .clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT, \
+ }
+
/* Exported globals */
extern struct clk_ops kona_peri_clk_ops;
-/* Help functions */
-
-#define KONA_CLK_SETUP(_ccu, _type, _name) \
- kona_clk_setup((_ccu), #_name, bcm_clk_## _type, &_name ## _data)
-
-#define PERI_CLK_SETUP(_ccu, _id, _name) \
- (_ccu)->clk_data.clks[_id] = KONA_CLK_SETUP((_ccu), peri, _name)
-
/* Externally visible functions */
extern u64 do_div_round_closest(u64 dividend, unsigned long divisor);
@@ -412,11 +418,9 @@ extern u64 scaled_div_max(struct bcm_clk_div *div);
extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value,
u32 billionths);
-extern struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
- enum bcm_clk_type type, void *data);
+extern struct clk *kona_clk_setup(struct kona_clk *bcm_clk);
extern void __init kona_dt_ccu_setup(struct ccu_data *ccu,
- struct device_node *node,
- int (*ccu_clks_setup)(struct ccu_data *));
+ struct device_node *node);
extern bool __init kona_ccu_init(struct ccu_data *ccu);
#endif /* _CLK_KONA_H */
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 04/12] clk: bcm281xx: initialize CCU structures statically
From: Alex Elder @ 2014-02-26 0:15 UTC (permalink / raw)
To: mturquette, mporter, bcm, galak, ijc+devicetree, mark.rutland,
pawel.moll, robh+dt
Cc: bcm-kernel-feedback-list, linux-arm-kernel, devicetree,
linux-kernel
In-Reply-To: <1393373752-30875-1-git-send-email-elder@linaro.org>
We know up front how many CCU's we'll support, so there's no need to
allocate their data structures dynamically. Define a macro
KONA_CCU_COMMON() to simplify the initialization of many of the
fields in a ccu_data structure. Pass the address of a statically
defined CCU structure to kona_dt_ccu_setup() rather than having that
function allocate one.
We also know at build time how many clocks a given CCU will provide,
though the number of of them for each CCU is different. Record the
number of clocks we need in the CCU's clk_onecell_data struct
(which is used when we register the CCU with the common clock code
as a clock provider). Rename that struct field "clk_data" (because
"data" alone gets a little confusing).
Use the known clock count to move the allocation of each CCU's
clocks array into ccu_clks_setup() rather than having each CCU's
setup callback function do it.
(The real motivation behind all of this is that we'll be doing some
static initialization of some additional CCU-specific data soon.)
Signed-off-by: Alex Elder <elder@linaro.org>
---
drivers/clk/bcm/clk-bcm281xx.c | 144 +++++++++++++++-----------------------
drivers/clk/bcm/clk-kona-setup.c | 47 ++++++-------
drivers/clk/bcm/clk-kona.c | 4 +-
drivers/clk/bcm/clk-kona.h | 21 ++++--
4 files changed, 97 insertions(+), 119 deletions(-)
diff --git a/drivers/clk/bcm/clk-bcm281xx.c b/drivers/clk/bcm/clk-bcm281xx.c
index bb947af..d72f2ae 100644
--- a/drivers/clk/bcm/clk-bcm281xx.c
+++ b/drivers/clk/bcm/clk-bcm281xx.c
@@ -15,6 +15,9 @@
#include "clk-kona.h"
#include "dt-bindings/clock/bcm281xx.h"
+#define BCM281XX_CCU_COMMON(_name, _ucase_name) \
+ KONA_CCU_COMMON(BCM281XX, _name, _ucase_name)
+
/*
* These are the bcm281xx CCU device tree "compatible" strings.
* We're stuck with using "bcm11351" in the string because wild
@@ -27,7 +30,7 @@
#define BCM281XX_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu"
#define BCM281XX_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu"
-/* Root CCU clocks */
+/* Root CCU */
static struct peri_clk_data frac_1m_data = {
.gate = HW_SW_GATE(0x214, 16, 0, 1),
@@ -36,7 +39,11 @@ static struct peri_clk_data frac_1m_data = {
.clocks = CLOCKS("ref_crystal"),
};
-/* AON CCU clocks */
+static struct ccu_data root_ccu_data = {
+ BCM281XX_CCU_COMMON(root, ROOT),
+};
+
+/* AON CCU */
static struct peri_clk_data hub_timer_data = {
.gate = HW_SW_GATE(0x0414, 16, 0, 1),
@@ -65,7 +72,11 @@ static struct peri_clk_data pmu_bsc_var_data = {
.trig = TRIGGER(0x0a40, 2),
};
-/* Hub CCU clocks */
+static struct ccu_data aon_ccu_data = {
+ BCM281XX_CCU_COMMON(aon, AON),
+};
+
+/* Hub CCU */
static struct peri_clk_data tmon_1m_data = {
.gate = HW_SW_GATE(0x04a4, 18, 2, 3),
@@ -75,7 +86,11 @@ static struct peri_clk_data tmon_1m_data = {
.trig = TRIGGER(0x0e84, 1),
};
-/* Master CCU clocks */
+static struct ccu_data hub_ccu_data = {
+ BCM281XX_CCU_COMMON(hub, HUB),
+};
+
+/* Master CCU */
static struct peri_clk_data sdio1_data = {
.gate = HW_SW_GATE(0x0358, 18, 2, 3),
@@ -158,7 +173,11 @@ static struct peri_clk_data hsic2_12m_data = {
.trig = TRIGGER(0x0afc, 5),
};
-/* Slave CCU clocks */
+static struct ccu_data master_ccu_data = {
+ BCM281XX_CCU_COMMON(master, MASTER),
+};
+
+/* Slave CCU */
static struct peri_clk_data uartb_data = {
.gate = HW_SW_GATE(0x0400, 18, 2, 3),
@@ -266,6 +285,10 @@ static struct peri_clk_data pwm_data = {
.trig = TRIGGER(0x0afc, 15),
};
+static struct ccu_data slave_ccu_data = {
+ BCM281XX_CCU_COMMON(slave, SLAVE),
+};
+
/*
* CCU setup routines
*
@@ -277,107 +300,52 @@ static struct peri_clk_data pwm_data = {
*/
static int __init bcm281xx_root_ccu_clks_setup(struct ccu_data *ccu)
{
- struct clk **clks;
- size_t count = BCM281XX_ROOT_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate root clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_ROOT_CCU_FRAC_1M, frac_1m);
+ PERI_CLK_SETUP(ccu, BCM281XX_ROOT_CCU_FRAC_1M, frac_1m);
return 0;
}
static int __init bcm281xx_aon_ccu_clks_setup(struct ccu_data *ccu)
{
- struct clk **clks;
- size_t count = BCM281XX_AON_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate aon clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_HUB_TIMER, hub_timer);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC, pmu_bsc);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC_VAR, pmu_bsc_var);
+ PERI_CLK_SETUP(ccu, BCM281XX_AON_CCU_HUB_TIMER, hub_timer);
+ PERI_CLK_SETUP(ccu, BCM281XX_AON_CCU_PMU_BSC, pmu_bsc);
+ PERI_CLK_SETUP(ccu, BCM281XX_AON_CCU_PMU_BSC_VAR, pmu_bsc_var);
return 0;
}
static int __init bcm281xx_hub_ccu_clks_setup(struct ccu_data *ccu)
{
- struct clk **clks;
- size_t count = BCM281XX_HUB_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate hub clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_HUB_CCU_TMON_1M, tmon_1m);
+ PERI_CLK_SETUP(ccu, BCM281XX_HUB_CCU_TMON_1M, tmon_1m);
return 0;
}
static int __init bcm281xx_master_ccu_clks_setup(struct ccu_data *ccu)
{
- struct clk **clks;
- size_t count = BCM281XX_MASTER_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate master clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO1, sdio1);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO2, sdio2);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO3, sdio3);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO4, sdio4);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_USB_IC, usb_ic);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_48M, hsic2_48m);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_12M, hsic2_12m);
+ PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_SDIO1, sdio1);
+ PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_SDIO2, sdio2);
+ PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_SDIO3, sdio3);
+ PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_SDIO4, sdio4);
+ PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_USB_IC, usb_ic);
+ PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_HSIC2_48M, hsic2_48m);
+ PERI_CLK_SETUP(ccu, BCM281XX_MASTER_CCU_HSIC2_12M, hsic2_12m);
return 0;
}
static int __init bcm281xx_slave_ccu_clks_setup(struct ccu_data *ccu)
{
- struct clk **clks;
- size_t count = BCM281XX_SLAVE_CCU_CLOCK_COUNT;
-
- clks = kzalloc(count * sizeof(*clks), GFP_KERNEL);
- if (!clks) {
- pr_err("%s: failed to allocate slave clocks\n", __func__);
- return -ENOMEM;
- }
- ccu->data.clks = clks;
- ccu->data.clk_num = count;
-
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB, uartb);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB2, uartb2);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB3, uartb3);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB4, uartb4);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP0, ssp0);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP2, ssp2);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC1, bsc1);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC2, bsc2);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC3, bsc3);
- PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_PWM, pwm);
+ PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_UARTB, uartb);
+ PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_UARTB2, uartb2);
+ PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_UARTB3, uartb3);
+ PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_UARTB4, uartb4);
+ PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_SSP0, ssp0);
+ PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_SSP2, ssp2);
+ PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_BSC1, bsc1);
+ PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_BSC2, bsc2);
+ PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_BSC3, bsc3);
+ PERI_CLK_SETUP(ccu, BCM281XX_SLAVE_CCU_PWM, pwm);
return 0;
}
@@ -386,27 +354,29 @@ static int __init bcm281xx_slave_ccu_clks_setup(struct ccu_data *ccu)
static void __init kona_dt_root_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_root_ccu_clks_setup);
+ kona_dt_ccu_setup(&root_ccu_data, node, bcm281xx_root_ccu_clks_setup);
}
static void __init kona_dt_aon_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_aon_ccu_clks_setup);
+ kona_dt_ccu_setup(&aon_ccu_data, node, bcm281xx_aon_ccu_clks_setup);
}
static void __init kona_dt_hub_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_hub_ccu_clks_setup);
+ kona_dt_ccu_setup(&hub_ccu_data, node, bcm281xx_hub_ccu_clks_setup);
}
static void __init kona_dt_master_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_master_ccu_clks_setup);
+ kona_dt_ccu_setup(&master_ccu_data, node,
+ bcm281xx_master_ccu_clks_setup);
}
static void __init kona_dt_slave_ccu_setup(struct device_node *node)
{
- kona_dt_ccu_setup(node, bcm281xx_slave_ccu_clks_setup);
+ kona_dt_ccu_setup(&slave_ccu_data, node,
+ bcm281xx_slave_ccu_clks_setup);
}
CLK_OF_DECLARE(bcm281xx_root_ccu, BCM281XX_DT_ROOT_CCU_COMPAT,
diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c
index eed84f5..4468065 100644
--- a/drivers/clk/bcm/clk-kona-setup.c
+++ b/drivers/clk/bcm/clk-kona-setup.c
@@ -674,50 +674,49 @@ static void ccu_clks_teardown(struct ccu_data *ccu)
{
u32 i;
- for (i = 0; i < ccu->data.clk_num; i++)
- kona_clk_teardown(ccu->data.clks[i]);
- kfree(ccu->data.clks);
+ for (i = 0; i < ccu->clk_data.clk_num; i++)
+ kona_clk_teardown(ccu->clk_data.clks[i]);
+ kfree(ccu->clk_data.clks);
}
static void kona_ccu_teardown(struct ccu_data *ccu)
{
- if (!ccu)
- return;
-
+ kfree(ccu->clk_data.clks);
+ ccu->clk_data.clks = NULL;
if (!ccu->base)
- goto done;
+ return;
of_clk_del_provider(ccu->node); /* safe if never added */
ccu_clks_teardown(ccu);
list_del(&ccu->links);
of_node_put(ccu->node);
+ ccu->node = NULL;
iounmap(ccu->base);
-done:
- kfree(ccu->name);
- kfree(ccu);
+ ccu->base = NULL;
}
/*
* Set up a CCU. Call the provided ccu_clks_setup callback to
* initialize the array of clocks provided by the CCU.
*/
-void __init kona_dt_ccu_setup(struct device_node *node,
+void __init kona_dt_ccu_setup(struct ccu_data *ccu,
+ struct device_node *node,
int (*ccu_clks_setup)(struct ccu_data *))
{
- struct ccu_data *ccu;
struct resource res = { 0 };
resource_size_t range;
int ret;
- ccu = kzalloc(sizeof(*ccu), GFP_KERNEL);
- if (ccu)
- ccu->name = kstrdup(node->name, GFP_KERNEL);
- if (!ccu || !ccu->name) {
- pr_err("%s: unable to allocate CCU struct for %s\n",
- __func__, node->name);
- kfree(ccu);
+ if (ccu->clk_data.clk_num) {
+ size_t size;
- return;
+ size = ccu->clk_data.clk_num * sizeof(*ccu->clk_data.clks);
+ ccu->clk_data.clks = kzalloc(size, GFP_KERNEL);
+ if (!ccu->clk_data.clks) {
+ pr_err("%s: unable to allocate %u clocks for %s\n",
+ __func__, ccu->clk_data.clk_num, node->name);
+ return;
+ }
}
ret = of_address_to_resource(node, 0, &res);
@@ -741,18 +740,14 @@ void __init kona_dt_ccu_setup(struct device_node *node,
node->name);
goto out_err;
}
-
- spin_lock_init(&ccu->lock);
- INIT_LIST_HEAD(&ccu->links);
ccu->node = of_node_get(node);
-
list_add_tail(&ccu->links, &ccu_list);
- /* Set up clocks array (in ccu->data) */
+ /* Set up clocks array (in ccu->clk_data) */
if (ccu_clks_setup(ccu))
goto out_err;
- ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->data);
+ ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->clk_data);
if (ret) {
pr_err("%s: error adding ccu %s as provider (%d)\n", __func__,
node->name, ret);
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index 488ed1f..5c0dc5b 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -1018,13 +1018,13 @@ bool __init kona_ccu_init(struct ccu_data *ccu)
{
unsigned long flags;
unsigned int which;
- struct clk **clks = ccu->data.clks;
+ struct clk **clks = ccu->clk_data.clks;
bool success = true;
flags = ccu_lock(ccu);
__ccu_write_enable(ccu);
- for (which = 0; which < ccu->data.clk_num; which++) {
+ for (which = 0; which < ccu->clk_data.clk_num; which++) {
struct kona_clk *bcm_clk;
if (!clks[which])
diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h
index 96fd0bc..0748c9b 100644
--- a/drivers/clk/bcm/clk-kona.h
+++ b/drivers/clk/bcm/clk-kona.h
@@ -85,11 +85,20 @@ struct ccu_data {
bool write_enabled; /* write access is currently enabled */
struct list_head links; /* for ccu_list */
struct device_node *node;
- struct clk_onecell_data data;
+ struct clk_onecell_data clk_data;
const char *name;
u32 range; /* byte range of address space */
};
+/* Initialization for common fields in a Kona ccu_data structure */
+#define KONA_CCU_COMMON(_prefix, _name, _ucase_name) \
+ .name = #_name "_ccu", \
+ .lock = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock), \
+ .links = LIST_HEAD_INIT(_name ## _ccu_data.links), \
+ .clk_data = { \
+ .clk_num = _prefix ## _ ## _ucase_name ## _CCU_CLOCK_COUNT, \
+ }
+
/*
* Gating control and status is managed by a 32-bit gate register.
*
@@ -390,8 +399,11 @@ extern struct clk_ops kona_peri_clk_ops;
/* Help functions */
-#define PERI_CLK_SETUP(clks, ccu, id, name) \
- clks[id] = kona_clk_setup(ccu, #name, bcm_clk_peri, &name ## _data)
+#define KONA_CLK_SETUP(_ccu, _type, _name) \
+ kona_clk_setup((_ccu), #_name, bcm_clk_## _type, &_name ## _data)
+
+#define PERI_CLK_SETUP(_ccu, _id, _name) \
+ (_ccu)->clk_data.clks[_id] = KONA_CLK_SETUP((_ccu), peri, _name)
/* Externally visible functions */
@@ -402,7 +414,8 @@ extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value,
extern struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
enum bcm_clk_type type, void *data);
-extern void __init kona_dt_ccu_setup(struct device_node *node,
+extern void __init kona_dt_ccu_setup(struct ccu_data *ccu,
+ struct device_node *node,
int (*ccu_clks_setup)(struct ccu_data *));
extern bool __init kona_ccu_init(struct ccu_data *ccu);
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 03/12] clk: bcm281xx: change some symbol names
From: Alex Elder @ 2014-02-26 0:15 UTC (permalink / raw)
To: mturquette, mporter, bcm, galak, ijc+devicetree, mark.rutland,
pawel.moll, robh+dt
Cc: devicetree, bcm-kernel-feedback-list, linux-kernel,
linux-arm-kernel
In-Reply-To: <1393373752-30875-1-git-send-email-elder@linaro.org>
As I developed the bcm281xx clock code I understood there were
restrictions on device tree "compatible" strings names, and as a
result "bcm11351" was used in places despite the part family being
more properly called "bcm281xx". This can be a little confusing.
In some cases I went to far and things using "bcm11351" when that
was not necessary.
This patch remedies this. It renames the symbol used to define the
"compatible" string (but not its value) so it uses "BCM281XX".
Similarly, the name names provided to the CLK_OF_DECLARE() macro
are changed, hoping to minimize the number of places that the
confusing "11351" string is used.
Signed-off-by: Alex Elder <elder@linaro.org>
---
drivers/clk/bcm/clk-bcm281xx.c | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/drivers/clk/bcm/clk-bcm281xx.c b/drivers/clk/bcm/clk-bcm281xx.c
index 3c66de6..bb947af 100644
--- a/drivers/clk/bcm/clk-bcm281xx.c
+++ b/drivers/clk/bcm/clk-bcm281xx.c
@@ -15,12 +15,17 @@
#include "clk-kona.h"
#include "dt-bindings/clock/bcm281xx.h"
-/* bcm11351 CCU device tree "compatible" strings */
-#define BCM11351_DT_ROOT_CCU_COMPAT "brcm,bcm11351-root-ccu"
-#define BCM11351_DT_AON_CCU_COMPAT "brcm,bcm11351-aon-ccu"
-#define BCM11351_DT_HUB_CCU_COMPAT "brcm,bcm11351-hub-ccu"
-#define BCM11351_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu"
-#define BCM11351_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu"
+/*
+ * These are the bcm281xx CCU device tree "compatible" strings.
+ * We're stuck with using "bcm11351" in the string because wild
+ * cards aren't allowed, and that name was the first one defined
+ * in this family of devices.
+ */
+#define BCM281XX_DT_ROOT_CCU_COMPAT "brcm,bcm11351-root-ccu"
+#define BCM281XX_DT_AON_CCU_COMPAT "brcm,bcm11351-aon-ccu"
+#define BCM281XX_DT_HUB_CCU_COMPAT "brcm,bcm11351-hub-ccu"
+#define BCM281XX_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu"
+#define BCM281XX_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu"
/* Root CCU clocks */
@@ -404,13 +409,13 @@ static void __init kona_dt_slave_ccu_setup(struct device_node *node)
kona_dt_ccu_setup(node, bcm281xx_slave_ccu_clks_setup);
}
-CLK_OF_DECLARE(bcm11351_root_ccu, BCM11351_DT_ROOT_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_root_ccu, BCM281XX_DT_ROOT_CCU_COMPAT,
kona_dt_root_ccu_setup);
-CLK_OF_DECLARE(bcm11351_aon_ccu, BCM11351_DT_AON_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_aon_ccu, BCM281XX_DT_AON_CCU_COMPAT,
kona_dt_aon_ccu_setup);
-CLK_OF_DECLARE(bcm11351_hub_ccu, BCM11351_DT_HUB_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_hub_ccu, BCM281XX_DT_HUB_CCU_COMPAT,
kona_dt_hub_ccu_setup);
-CLK_OF_DECLARE(bcm11351_master_ccu, BCM11351_DT_MASTER_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_master_ccu, BCM281XX_DT_MASTER_CCU_COMPAT,
kona_dt_master_ccu_setup);
-CLK_OF_DECLARE(bcm11351_slave_ccu, BCM11351_DT_SLAVE_CCU_COMPAT,
+CLK_OF_DECLARE(bcm281xx_slave_ccu, BCM281XX_DT_SLAVE_CCU_COMPAT,
kona_dt_slave_ccu_setup);
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 02/12] clk: bcm281xx: use init_data.name for clock name
From: Alex Elder @ 2014-02-26 0:15 UTC (permalink / raw)
To: mturquette, mporter, bcm, galak, ijc+devicetree, mark.rutland,
pawel.moll, robh+dt
Cc: bcm-kernel-feedback-list, linux-arm-kernel, devicetree,
linux-kernel
In-Reply-To: <1393373752-30875-1-git-send-email-elder@linaro.org>
Use the init_data.name field to hold the name of a Kona clock rather
than duplicating it.
Signed-off-by: Alex Elder <elder@linaro.org>
---
drivers/clk/bcm/clk-kona-setup.c | 6 +++---
drivers/clk/bcm/clk-kona.c | 17 ++++++++++-------
drivers/clk/bcm/clk-kona.h | 3 +--
3 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c
index c7607fe..eed84f5 100644
--- a/drivers/clk/bcm/clk-kona-setup.c
+++ b/drivers/clk/bcm/clk-kona-setup.c
@@ -64,7 +64,7 @@ static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk)
BUG_ON(bcm_clk->type != bcm_clk_peri);
peri = bcm_clk->peri;
- name = bcm_clk->name;
+ name = bcm_clk->init_data.name;
range = bcm_clk->ccu->range;
limit = range - sizeof(u32);
@@ -329,7 +329,7 @@ peri_clk_data_valid(struct kona_clk *bcm_clk)
return false;
peri = bcm_clk->peri;
- name = bcm_clk->name;
+ name = bcm_clk->init_data.name;
gate = &peri->gate;
if (gate_exists(gate) && !gate_valid(gate, "gate", name))
return false;
@@ -630,7 +630,7 @@ struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name,
return NULL;
}
bcm_clk->ccu = ccu;
- bcm_clk->name = name;
+ bcm_clk->init_data.name = name;
init_data = &bcm_clk->init_data;
init_data->name = name;
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index c01d810..488ed1f 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -807,7 +807,7 @@ static int kona_peri_clk_enable(struct clk_hw *hw)
struct kona_clk *bcm_clk = to_kona_clk(hw);
struct bcm_clk_gate *gate = &bcm_clk->peri->gate;
- return clk_gate(bcm_clk->ccu, bcm_clk->name, gate, true);
+ return clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, true);
}
static void kona_peri_clk_disable(struct clk_hw *hw)
@@ -815,7 +815,7 @@ static void kona_peri_clk_disable(struct clk_hw *hw)
struct kona_clk *bcm_clk = to_kona_clk(hw);
struct bcm_clk_gate *gate = &bcm_clk->peri->gate;
- (void)clk_gate(bcm_clk->ccu, bcm_clk->name, gate, false);
+ (void)clk_gate(bcm_clk->ccu, bcm_clk->init_data.name, gate, false);
}
static int kona_peri_clk_is_enabled(struct clk_hw *hw)
@@ -873,12 +873,13 @@ static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index)
ret = selector_write(bcm_clk->ccu, &data->gate, sel, trig, index);
if (ret == -ENXIO) {
- pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name);
+ pr_err("%s: gating failure for %s\n", __func__,
+ bcm_clk->init_data.name);
ret = -EIO; /* Don't proliferate weird errors */
} else if (ret == -EIO) {
pr_err("%s: %strigger failed for %s\n", __func__,
trig == &data->pre_trig ? "pre-" : "",
- bcm_clk->name);
+ bcm_clk->init_data.name);
}
return ret;
@@ -937,10 +938,12 @@ static int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate,
ret = divider_write(bcm_clk->ccu, &data->gate, &data->div,
&data->trig, scaled_div);
if (ret == -ENXIO) {
- pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name);
+ pr_err("%s: gating failure for %s\n", __func__,
+ bcm_clk->init_data.name);
ret = -EIO; /* Don't proliferate weird errors */
} else if (ret == -EIO) {
- pr_err("%s: trigger failed for %s\n", __func__, bcm_clk->name);
+ pr_err("%s: trigger failed for %s\n", __func__,
+ bcm_clk->init_data.name);
}
return ret;
@@ -962,7 +965,7 @@ static bool __peri_clk_init(struct kona_clk *bcm_clk)
{
struct ccu_data *ccu = bcm_clk->ccu;
struct peri_clk_data *peri = bcm_clk->peri;
- const char *name = bcm_clk->name;
+ const char *name = bcm_clk->init_data.name;
struct bcm_clk_trig *trig;
BUG_ON(bcm_clk->type != bcm_clk_peri);
diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h
index 5e139ad..96fd0bc 100644
--- a/drivers/clk/bcm/clk-kona.h
+++ b/drivers/clk/bcm/clk-kona.h
@@ -373,8 +373,7 @@ struct peri_clk_data {
struct kona_clk {
struct clk_hw hw;
- struct clk_init_data init_data;
- const char *name; /* name of this clock */
+ struct clk_init_data init_data; /* includes name of this clock */
struct ccu_data *ccu; /* ccu this clock is associated with */
enum bcm_clk_type type;
union {
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox