* Re: [PATCH 2/2] ARM: dts: MSM8974: Add pinctrl node
From: Linus Walleij @ 2014-02-24 9:57 UTC (permalink / raw)
To: Ivan T. Ivanov
Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
Russell King, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1391700529-11816-2-git-send-email-iivanov-NEYub+7Iv8PQT0dZR+AlfA@public.gmane.org>
On Thu, Feb 6, 2014 at 4:28 PM, Ivan T. Ivanov <iivanov-NEYub+7Iv8PQT0dZR+AlfA@public.gmane.org> wrote:
> From: "Ivan T. Ivanov" <iivanov-NEYub+7Iv8PQT0dZR+AlfA@public.gmane.org>
>
> Add the pin control node and pin definitions of SPI8.
>
> Signed-off-by: Ivan T. Ivanov <iivanov-NEYub+7Iv8PQT0dZR+AlfA@public.gmane.org>
Acked-by: Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Kumar, please take this through your qcom tree.
Yours,
Linus Walleij
--
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
* Re: [PATCH 1/2] usb: dwc3: core: continue probing if usb phy library returns -ENODEV/-ENXIO
From: Kishon Vijay Abraham I @ 2014-02-24 9:55 UTC (permalink / raw)
To: Roger Quadros, Heikki Krogerus, Felipe Balbi
Cc: george.cherian, devicetree, linux-doc, linux-kernel, linux-omap,
linux-arm-kernel, linux-usb
In-Reply-To: <5307468E.6040304@ti.com>
On Friday 21 February 2014 05:59 PM, Roger Quadros wrote:
> On 02/21/2014 02:25 PM, Kishon Vijay Abraham I wrote:
>> Hi Roger,
>>
>> On Wednesday 19 February 2014 06:07 PM, Roger Quadros wrote:
>>> Hi,
>>>
>>> On 02/12/2014 11:46 AM, Kishon Vijay Abraham I wrote:
>>>> On Wednesday 29 January 2014 08:17 PM, Heikki Krogerus wrote:
>>>>> Hi,
>>>>>
>>>>> On Tue, Jan 28, 2014 at 10:30:36AM -0600, Felipe Balbi wrote:
>>>>>> On Tue, Jan 28, 2014 at 05:32:30PM +0200, Heikki Krogerus wrote:
>>>>>>> On Mon, Jan 27, 2014 at 10:05:20AM -0600, Felipe Balbi wrote:
>>>>>>> For the controller drivers the PHYs are just a resource like any
>>>>>>> other. The controller drivers can't have any responsibility of
>>>>>>> them. They should not care if PHY drivers are available for them or
>>>>>>> not, or even if the PHY framework is available or not.
>>>>>>
>>>>>> huh? If memory isn't available you don't continue probing, right ? If
>>>>>> your IORESOURCE_MEM is missing, you also don't continue probing, if your
>>>>>> IRQ line is missing, you bail too. Those are also nothing but resources
>>>>>> to the driver, what you're asking here is to treat PHY as a _different_
>>>>>> resource; which might be fine, but we need to make sure we don't
>>>>>> continue probing when a PHY is missing in a platform that certainly
>>>>>> needs a PHY.
>>>>>
>>>>> Yes, true. In my head I was comparing the PHY only to resources like
>>>>> gpios, clocks, dma channels, etc. that are often optional to the
>>>>> drivers.
>>>>>
>>>>>>>>>> But I really want to see the argument against using no-op. As far as I
>>>>>>>>>> could see, everybody needs a PHY driver one way or another, some
>>>>>>>>>> platforms just haven't sent any PHY driver upstream and have their own
>>>>>>>>>> hacked up solution to avoid using the PHY layer.
>>>>>>>>>
>>>>>>>>> Not true in our case. Platforms using Intel's SoCs and chip sets may
>>>>>>>>> or may not have controllable USB PHY. Quite often they don't. The
>>>>>>>>> Baytrails have usually ULPI PHY for USB2, but that does not mean they
>>>>>>>>> provide any vendor specific functions or any need for a driver in any
>>>>>>>>> case.
>>>>>>>>
>>>>>>>> that's different from what I heard.
>>>>>>>
>>>>>>> I don't know where you got that impression, but it's not true. The
>>>>>>> Baytrail SoCs for example don't have internal USB PHYs, which means
>>>>>>> the manufacturers using it can select what they want. So we have
>>>>>>> boards where PHY driver(s) is needed and boards where it isn't.
>>>>>>
>>>>>> alright, that explains it ;-) So you have external USB2 and USB3 PHYs ?
>>>>>> You have an external PIPE3 interface ? That's quite an achievement,
>>>>>> kudos to your HW designers. Getting timing closure on PIPE3 is a
>>>>>> difficult task.
>>>>>
>>>>> No, only the USB2 PHY is external. I'm giving you wrong information,
>>>>> I'm sorry about that. Need to concentrate on what I'm writing.
>>>>>
>>>>> <snip>
>>>>>
>>>>>>> This is really good to get. We have some projects where we are dealing
>>>>>>> with more embedded environments, like IVI, where the kernel should be
>>>>>>> stripped of everything useless. Since the PHYs are autonomous, we
>>>>>>> should be able to disable the PHY libraries/frameworks.
>>>>>>
>>>>>> hmmm, in that case it's a lot easier to treat. We can use
>>>>>> ERR_PTR(-ENXIO) as an indication that the framework is disabled, or
>>>>>> something like that.
>>>>>>
>>>>>> The difficult is really reliably supporting e.g. OMAP5 (which won't work
>>>>>> without a PHY) and your BayTrail with autonomous PHYs. What can we use
>>>>>> as an indication ?
>>>>>
>>>>> OMAP has it's own glue driver, so shouldn't it depend on the PHY
>>>>> layer?
>>>>
>>>> right, but the PHY is connected to the dwc3 core and not to the glue.
>>>>>
>>>>>> I mean, I need to know that a particular platform depends on a PHY
>>>>>> driver before I decide to return -EPROBE_DEFER or just assume the PHY
>>>>>> isn't needed ;-)
>>>>>
>>>>> I don't think dwc3 (core) should care about that. The PHY layer needs
>>>>> to tell us that. If the PHY driver that the platform depends is not
>>>>> available yet, the PHY layer returns -EPROBE_DEFER and dwc3 ends up
>>>>> returning -EPROBE_DEFER.
>>>>
>>>> I don't think the PHY layer can 'reliably' tell if PHY driver is available or
>>>> not. Consider when the phy_provider_register fails, there is no way to know if
>>>> PHY driver is available or not. There are a few cases where PHY layer returns
>>>> -EPROBE_DEFER but none of them can tell for sure that PHY driver is either
>>>> available and failed or not available at all. It would be best for us to leave
>>>> that to the platforms if we want to be sure if the platform needs a PHY or not.
>>>>
>>>
>>> Just to summarize this thread on what we need
>>
>> Thanks for summarizing.
>>>
>>> 1) dwc3 core shouldn't worry about platform specific stuff i.e. PHY needed or not.
>>> It should be as generic as possible.
I think this contradicts with Felipe's requirement of
dwc3 core bailing out if a particular platform needs a PHY but it's not able to
get it.
>>>
>>> 2) dwc3 core should continue probe even if PHY layer is not enabled, as not all platforms need it.
>>>
>>> 3) dwc3 core should continue probe if PHY device is not available. (-ENODEV?)
>>>
>>> 4) dwc3 core should error out on any error condition if PHY device is available and caused some error,
>>> e.g. init error.
>>>
>>> 5) dwc3 core should return EPROBE_DEFER if PHY device is available but device driver is not yet loaded.
>>>
>>> 6) platform glue should do the necessary sanity checks for availability of all resources like PHY device, PHY layer, etc, before populating the dwc3 device. e.g. in OMAP5 case we could check if both usb2 and usb3 PHY
>>> nodes are available in the DT and PHY layer is enabled, from dwc3-omap.c? In J6 case we could check that at least usb2 phy node is there for the High-Speed only controller, and so on.
>>
>> The PHY is connected to the dwc3 core. So I'm not sure if we should be doing
>> checks for PHY in the glue layer.
>
> Sorry, I didn't get you. My reasoning was that since OMAP platform has this strict requirement of requiring
> explicit PHY control in order to work, we must do the sanity checks in OMAP specific code and not in the dwc3 core code. It has nothing to do with how hardware is laid out.
>
> What alternative do you suggest otherwise?
Thanks
Kishon
^ permalink raw reply
* Re: [PATCH 1/2] usb: dwc3: core: continue probing if usb phy library returns -ENODEV/-ENXIO
From: Kishon Vijay Abraham I @ 2014-02-24 9:51 UTC (permalink / raw)
To: Roger Quadros, Heikki Krogerus, Felipe Balbi
Cc: devicetree, george.cherian, linux-doc, linux-usb, linux-kernel,
linux-omap, linux-arm-kernel
In-Reply-To: <5307468E.6040304@ti.com>
Hi Roger,
On Friday 21 February 2014 05:59 PM, Roger Quadros wrote:
> On 02/21/2014 02:25 PM, Kishon Vijay Abraham I wrote:
>> Hi Roger,
>>
>> On Wednesday 19 February 2014 06:07 PM, Roger Quadros wrote:
>>> Hi,
>>>
>>> On 02/12/2014 11:46 AM, Kishon Vijay Abraham I wrote:
>>>> On Wednesday 29 January 2014 08:17 PM, Heikki Krogerus wrote:
>>>>> Hi,
>>>>>
>>>>> On Tue, Jan 28, 2014 at 10:30:36AM -0600, Felipe Balbi wrote:
>>>>>> On Tue, Jan 28, 2014 at 05:32:30PM +0200, Heikki Krogerus wrote:
>>>>>>> On Mon, Jan 27, 2014 at 10:05:20AM -0600, Felipe Balbi wrote:
>>>>>>> For the controller drivers the PHYs are just a resource like any
>>>>>>> other. The controller drivers can't have any responsibility of
>>>>>>> them. They should not care if PHY drivers are available for them or
>>>>>>> not, or even if the PHY framework is available or not.
>>>>>>
>>>>>> huh? If memory isn't available you don't continue probing, right ? If
>>>>>> your IORESOURCE_MEM is missing, you also don't continue probing, if your
>>>>>> IRQ line is missing, you bail too. Those are also nothing but resources
>>>>>> to the driver, what you're asking here is to treat PHY as a _different_
>>>>>> resource; which might be fine, but we need to make sure we don't
>>>>>> continue probing when a PHY is missing in a platform that certainly
>>>>>> needs a PHY.
>>>>>
>>>>> Yes, true. In my head I was comparing the PHY only to resources like
>>>>> gpios, clocks, dma channels, etc. that are often optional to the
>>>>> drivers.
>>>>>
>>>>>>>>>> But I really want to see the argument against using no-op. As far as I
>>>>>>>>>> could see, everybody needs a PHY driver one way or another, some
>>>>>>>>>> platforms just haven't sent any PHY driver upstream and have their own
>>>>>>>>>> hacked up solution to avoid using the PHY layer.
>>>>>>>>>
>>>>>>>>> Not true in our case. Platforms using Intel's SoCs and chip sets may
>>>>>>>>> or may not have controllable USB PHY. Quite often they don't. The
>>>>>>>>> Baytrails have usually ULPI PHY for USB2, but that does not mean they
>>>>>>>>> provide any vendor specific functions or any need for a driver in any
>>>>>>>>> case.
>>>>>>>>
>>>>>>>> that's different from what I heard.
>>>>>>>
>>>>>>> I don't know where you got that impression, but it's not true. The
>>>>>>> Baytrail SoCs for example don't have internal USB PHYs, which means
>>>>>>> the manufacturers using it can select what they want. So we have
>>>>>>> boards where PHY driver(s) is needed and boards where it isn't.
>>>>>>
>>>>>> alright, that explains it ;-) So you have external USB2 and USB3 PHYs ?
>>>>>> You have an external PIPE3 interface ? That's quite an achievement,
>>>>>> kudos to your HW designers. Getting timing closure on PIPE3 is a
>>>>>> difficult task.
>>>>>
>>>>> No, only the USB2 PHY is external. I'm giving you wrong information,
>>>>> I'm sorry about that. Need to concentrate on what I'm writing.
>>>>>
>>>>> <snip>
>>>>>
>>>>>>> This is really good to get. We have some projects where we are dealing
>>>>>>> with more embedded environments, like IVI, where the kernel should be
>>>>>>> stripped of everything useless. Since the PHYs are autonomous, we
>>>>>>> should be able to disable the PHY libraries/frameworks.
>>>>>>
>>>>>> hmmm, in that case it's a lot easier to treat. We can use
>>>>>> ERR_PTR(-ENXIO) as an indication that the framework is disabled, or
>>>>>> something like that.
>>>>>>
>>>>>> The difficult is really reliably supporting e.g. OMAP5 (which won't work
>>>>>> without a PHY) and your BayTrail with autonomous PHYs. What can we use
>>>>>> as an indication ?
>>>>>
>>>>> OMAP has it's own glue driver, so shouldn't it depend on the PHY
>>>>> layer?
>>>>
>>>> right, but the PHY is connected to the dwc3 core and not to the glue.
>>>>>
>>>>>> I mean, I need to know that a particular platform depends on a PHY
>>>>>> driver before I decide to return -EPROBE_DEFER or just assume the PHY
>>>>>> isn't needed ;-)
>>>>>
>>>>> I don't think dwc3 (core) should care about that. The PHY layer needs
>>>>> to tell us that. If the PHY driver that the platform depends is not
>>>>> available yet, the PHY layer returns -EPROBE_DEFER and dwc3 ends up
>>>>> returning -EPROBE_DEFER.
>>>>
>>>> I don't think the PHY layer can 'reliably' tell if PHY driver is available or
>>>> not. Consider when the phy_provider_register fails, there is no way to know if
>>>> PHY driver is available or not. There are a few cases where PHY layer returns
>>>> -EPROBE_DEFER but none of them can tell for sure that PHY driver is either
>>>> available and failed or not available at all. It would be best for us to leave
>>>> that to the platforms if we want to be sure if the platform needs a PHY or not.
>>>>
>>>
>>> Just to summarize this thread on what we need
>>
>> Thanks for summarizing.
>>>
>>> 1) dwc3 core shouldn't worry about platform specific stuff i.e. PHY needed or not.
>>> It should be as generic as possible.
>>>
>>> 2) dwc3 core should continue probe even if PHY layer is not enabled, as not all platforms need it.
>>>
>>> 3) dwc3 core should continue probe if PHY device is not available. (-ENODEV?)
>>>
>>> 4) dwc3 core should error out on any error condition if PHY device is available and caused some error,
>>> e.g. init error.
>>>
>>> 5) dwc3 core should return EPROBE_DEFER if PHY device is available but device driver is not yet loaded.
>>>
>>> 6) platform glue should do the necessary sanity checks for availability of all resources like PHY device, PHY layer, etc, before populating the dwc3 device. e.g. in OMAP5 case we could check if both usb2 and usb3 PHY
>>> nodes are available in the DT and PHY layer is enabled, from dwc3-omap.c? In J6 case we could check that at least usb2 phy node is there for the High-Speed only controller, and so on.
>>
>> The PHY is connected to the dwc3 core. So I'm not sure if we should be doing
>> checks for PHY in the glue layer.
>
> Sorry, I didn't get you. My reasoning was that since OMAP platform has this strict requirement of requiring
> explicit PHY control in order to work, we must do the sanity checks in OMAP specific code and not in the dwc3 core code. It has nothing to do with how hardware is laid out.
What kind of sanity check do you think can be done in OMAP code? We don't use
any of the PHY API's in glue code. If we add the same PHY APIs in glue code it
will be duplication of the same code without much value besides breaking the
design guideline of the software to be modelled similar to hardware.
However in Kconfig of dwc3 glue we can add 'select GENERIC_PHY, select
PHY_OMAP_USB2, select OMAP_USB3' I guess.
Thanks
Kishon
^ permalink raw reply
* Re: [PATCH v3 1/4] ARM: sunxi: Add driver for sunxi usb phy
From: Kishon Vijay Abraham I @ 2014-02-24 9:39 UTC (permalink / raw)
To: Hans de Goede, Maxime Ripard
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <1393157352-21104-2-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Hi,
On Sunday 23 February 2014 05:39 PM, Hans de Goede wrote:
> The Allwinner A1x / A2x SoCs have 2 or 3 usb phys which are all accessed
> through a single set of registers. Besides this there are also some other
> phy related bits which need poking, which are per phy, but shared between the
> ohci and ehci controllers, so these are also controlled from this new phy
> driver.
>
> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> ---
> .../devicetree/bindings/phy/sun4i-usb-phy.txt | 26 ++
> drivers/phy/Kconfig | 11 +
> drivers/phy/Makefile | 1 +
> drivers/phy/phy-sun4i-usb.c | 329 +++++++++++++++++++++
> 4 files changed, 367 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
> create mode 100644 drivers/phy/phy-sun4i-usb.c
>
> diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
> new file mode 100644
> index 0000000..a82361b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
> @@ -0,0 +1,26 @@
> +Allwinner sun4i USB PHY
> +-----------------------
> +
> +Required properties:
> +- compatible : should be one of "allwinner,sun4i-a10-usb-phy",
> + "allwinner,sun5i-a13-usb-phy" or "allwinner,sun7i-a20-usb-phy"
> +- reg : a list of offset + length pairs
> +- reg-names : "phy_ctrl", "pmu1" and for sun4i or sun7i "pmu2"
> +- #phy-cells : from the generic phy bindings, must be 1
> +- clocks : phandle + clock specifier for the phy clock
> +- clock-names : "usb_phy"
> +- resets : a list of phandle + reset specifier pairs
> +- reset-names : "usb0_reset", "usb1_reset" and for sun4i or sun7i "usb2_reset"
> +
> +Example:
> + usbphy: phy@0x01c13400 {
> + #phy-cells = <1>;
> + compatible = "allwinner,sun4i-a10-usb-phy";
> + /* phy base regs, phy1 pmu reg, phy2 pmu reg */
> + reg = <0x01c13400 0x10 0x01c14800 0x4 0x01c1c800 0x4>;
> + reg-names = "phy_ctrl", "pmu1", "pmu2";
> + clocks = <&usb_clk 8>;
> + clock-names = "usb_phy";
> + resets = <&usb_clk 1>, <&usb_clk 2>;
> + reset-names = "usb1_reset", "usb2_reset";
> + };
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 4ef8755..6e336b4 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -64,4 +64,15 @@ config BCM_KONA_USB2_PHY
> help
> Enable this to support the Broadcom Kona USB 2.0 PHY.
>
> +config PHY_SUN4I_USB
> + tristate "Allwinner sunxi SoC USB PHY driver"
> + depends on ARCH_SUNXI
> + select GENERIC_PHY
recently some errors have been reported if you don't have depends on HAS_IOMEM.
Also add depends on CONFIG_OF.
> + help
> + Enable this to support the transceiver that is part of Allwinner
> + sunxi SoCs.
> +
> + This driver controls the entire USB PHY block, both the USB OTG
> + parts, as well as the 2 regular USB 2 host PHYs.
> +
> endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index b57c253..9d4f8bb 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -9,3 +9,4 @@ obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o
> obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
> obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o
> obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
> +obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o
> diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
> new file mode 100644
> index 0000000..31c4611
> --- /dev/null
> +++ b/drivers/phy/phy-sun4i-usb.c
> @@ -0,0 +1,329 @@
> +/*
> + * Allwinner sun4i USB phy driver
> + *
> + * Copyright (C) 2014 Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> + *
> + * Based on code from
> + * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
> + *
> + * Modelled after: Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Sylwester Nawrocki <s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/reset.h>
> +
> +#define REG_ISCR 0x00
> +#define REG_PHYCTL 0x04
> +#define REG_PHYBIST 0x08
> +#define REG_PHYTUNE 0x0c
> +
> +#define SUNXI_AHB_ICHR8_EN BIT(10)
> +#define SUNXI_AHB_INCR4_BURST_EN BIT(9)
> +#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
> +#define SUNXI_ULPI_BYPASS_EN BIT(0)
> +
> +/* Common Control Bits for Both PHYs */
> +#define PHY_PLL_BW 0x03
> +#define PHY_RES45_CAL_EN 0x0c
> +
> +/* Private Control Bits for Each PHY */
> +#define PHY_TX_AMPLITUDE_TUNE 0x20
> +#define PHY_TX_SLEWRATE_TUNE 0x22
> +#define PHY_VBUSVALID_TH_SEL 0x25
> +#define PHY_PULLUP_RES_SEL 0x27
> +#define PHY_OTG_FUNC_EN 0x28
> +#define PHY_VBUS_DET_EN 0x29
> +#define PHY_DISCON_TH_SEL 0x2a
> +
> +#define MAX_PHYS 3
> +
> +struct sun4i_usb_phy_data {
> + struct clk *clk;
> + void __iomem *base;
> + struct mutex mutex;
> + int num_phys;
> + u32 disc_thresh;
> + struct sun4i_usb_phy {
> + struct phy *phy;
> + void __iomem *pmu;
> + struct regulator *vbus;
> + struct reset_control *reset;
> + int index;
> + } phys[MAX_PHYS];
> +};
> +
> +#define to_sun4i_usb_phy_data(phy) \
> + container_of((phy), struct sun4i_usb_phy_data, phys[(phy)->index])
> +
> +static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
> + int len)
> +{
> + struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy);
> + u32 temp, usbc_bit = BIT(phy->index * 2);
> + int i;
> +
> + mutex_lock(&phy_data->mutex);
> +
> + for (i = 0; i < len; i++) {
> + temp = readl(phy_data->base + REG_PHYCTL);
> +
> + /* clear the address portion */
> + temp &= ~(0xff << 8);
> +
> + /* set the address */
> + temp |= ((addr + i) << 8);
> + writel(temp, phy_data->base + REG_PHYCTL);
> +
> + /* set the data bit and clear usbc bit*/
> + temp = readb(phy_data->base + REG_PHYCTL);
> + if (data & 0x1)
> + temp |= BIT(7);
>From the comment, I assume it to be a data bit. Let's add a macro for it?
If you can fix these minor comments while changing the $subject (PHY: sunxi) it
should be good to get merged.
Thanks
Kishon
^ permalink raw reply
* Re: [PATCH v3 0/4] ARM: sunxi: Add driver for sunxi usb phy + usb dts bindings
From: Kishon Vijay Abraham I @ 2014-02-24 9:34 UTC (permalink / raw)
To: Hans de Goede, Maxime Ripard
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <1393157352-21104-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Hi,
On Sunday 23 February 2014 05:39 PM, Hans de Goede wrote:
> Hi Kishon, Maxime,
>
> Here is v3 of my sunxi-usb-phy driver it addresses all review remarks made
> in response to v2, and as such this should be the final version, changes:
>
> -Fix check for wrong variable in error handling path pointed out by wens
> -Switch to using reg-names to differentiate between the different register
> ranges needed
>
> Kishon, can you please queue up the 1st patch of this series for 3.15 ?
huh.. maybe I failed to notice that before but the $subject for that patch
should be 'PHY: sunxi...' and not 'ARM: sunxi..'. Can you fix that up?
Thanks
Kishon
>
> Maxime, can you please add patches 2-4 to your dt-for-3.15 branch? Note these
> are only the dtsi bits.
>
> I'm holding back all the board .dts patches until it is clear how we want to
> deal with the ahci + usb regulator bits. Specifically I'm waiting for an answer
> to this question:
>
> "I hope this helps explain my reasoning, as said I'm fine with
> either way, if you want to change over to a single file +
> explicit enabling, let me know and I'll respin the ahci dts
> patches. Note I'm going on vacation for a week starting Monday,
> so you likely won't get a new version until next weekend."
>
> In my last reply to "[PATCH v6 17/18] ARM: sun4i: dt: Add ahci / sata support"
>
> I've a feeling you (Maxime) want me to rework things in to a single dtsi
> for all common regulators + explicit enabling, which works for me, but before
> doing the necessary refactoring I would like to hear that this is what you
> want from you.
>
> Regards,
>
> Hans
>
>
> p.s.
>
> I'm going on vacation for 5 days leaving tomorrow, so I won't send the
> (refactored) board .dts file patches until next weekend.
>
>
^ permalink raw reply
* Re: [PATCH v3 1/4] ARM: sunxi: Add driver for sunxi usb phy
From: Maxime Ripard @ 2014-02-24 9:27 UTC (permalink / raw)
To: Hans de Goede
Cc: Kishon Vijay Abraham I,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <1393157352-21104-2-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 705 bytes --]
Hi,
On Sun, Feb 23, 2014 at 01:09:09PM +0100, Hans de Goede wrote:
> The Allwinner A1x / A2x SoCs have 2 or 3 usb phys which are all accessed
> through a single set of registers. Besides this there are also some other
> phy related bits which need poking, which are per phy, but shared between the
> ohci and ehci controllers, so these are also controlled from this new phy
> driver.
>
> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [RFCv2 5/5] mfd: twl4030-madc: Move driver to drivers/iio/adc
From: Peter Meerwald @ 2014-02-24 9:20 UTC (permalink / raw)
To: Sebastian Reichel
Cc: Sebastian Reichel, Marek Belisko, Jonathan Cameron, 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
In-Reply-To: <1393193271-16717-6-git-send-email-sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
> This is a driver for an A/D converter, which belongs into
> drivers/iio/adc.
like!
please find some comments below; not all might relate to the iio
conversion
I plan to test this on a beagleboard-xm
I always needed the following setup to make the twl4030_madc work for me
/* TWL4030 CATKIT_ANA_CTRL Register */
#define TWL4030_CARKIT_ANA_CTRL 0xBB
#define SEL_MADC_MCPC (1 << 3)
/*
* set SEL_MADC_MCPC in CARKIT_ANA_CTRL
* makes ADCIN3 to ADCIN6 available to the MADC
*/
twl_i2c_read_u8(TWL4030_MODULE_USB, &pin_mux,
TWL4030_CARKIT_ANA_CTRL);
pin_mux |= SEL_MADC_MCPC;
twl_i2c_write_u8(TWL4030_MODULE_USB, pin_mux,
TWL4030_CARKIT_ANA_CTRL);
regards, p.
> Signed-off-by: Sebastian Reichel <sre-8fiUuRrzOP0dnm+yROfE0A@public.gmane.org>
> ---
> drivers/iio/adc/Kconfig | 10 +
> drivers/iio/adc/Makefile | 1 +
> drivers/iio/adc/twl4030-madc.c | 914 +++++++++++++++++++++++++++++++++++++++++
> drivers/mfd/Kconfig | 10 -
> drivers/mfd/Makefile | 1 -
> drivers/mfd/twl4030-madc.c | 914 -----------------------------------------
> 6 files changed, 925 insertions(+), 925 deletions(-)
> create mode 100644 drivers/iio/adc/twl4030-madc.c
> delete mode 100644 drivers/mfd/twl4030-madc.c
>
> 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/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c
> new file mode 100644
> index 0000000..0bc79a7
> --- /dev/null
> +++ b/drivers/iio/adc/twl4030-madc.c
> @@ -0,0 +1,914 @@
> +/*
> + *
> + * TWL4030 MADC module driver-This driver monitors the real time
> + * conversion of analog signals like battery temperature,
> + * battery type, battery level etc.
> + *
> + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
> + * J Keerthy <j-keerthy-l0cyMroinI0@public.gmane.org>
> + *
> + * Based on twl4030-madc.c
> + * Copyright (C) 2008 Nokia Corporation
> + * Mikko Ylinen <mikko.k.ylinen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
> + *
> + * Amit Kucheria <amit.kucheria-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#include <linux/init.h>
> +#include <linux/device.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/delay.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/i2c/twl.h>
> +#include <linux/i2c/twl4030-madc.h>
> +#include <linux/module.h>
> +#include <linux/stddef.h>
> +#include <linux/mutex.h>
> +#include <linux/bitops.h>
> +#include <linux/jiffies.h>
> +#include <linux/types.h>
> +#include <linux/gfp.h>
> +#include <linux/err.h>
> +
> +#include <linux/iio/iio.h>
> +
> +/*
this could/should be kerneldoc, hecen /**
> + * 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
> + * @imr - Interrupt mask register of MADC
> + * @isr - Interrupt status register of MADC
> + */
> +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;
> + u8 imr;
> + u8 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 = 0;
> + req.func_cb = NULL;
> + 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 {
> + s16 numerator;
> + s16 denominator;
> +};
> +
> +static const struct twl4030_prescale_divider_ratios
> +twl4030_divider_ratios[16] = {
> + {1, 1}, /* CHANNEL 0 No Prescaler */
> + {1, 1}, /* CHANNEL 1 No Prescaler */
> + {6, 10}, /* CHANNEL 2 */
> + {6, 10}, /* CHANNEL 3 */
> + {6, 10}, /* CHANNEL 4 */
> + {6, 10}, /* CHANNEL 5 */
> + {6, 10}, /* CHANNEL 6 */
> + {6, 10}, /* CHANNEL 7 */
> + {3, 14}, /* CHANNEL 8 */
> + {1, 3}, /* CHANNEL 9 */
> + {1, 1}, /* CHANNEL 10 No Prescaler */
> + {15, 100}, /* CHANNEL 11 */
> + {1, 4}, /* CHANNEL 12 */
> + {1, 1}, /* CHANNEL 13 Reserved channels */
> + {1, 1}, /* CHANNEL 14 Reseved channels */
> + {5, 11}, /* CHANNEL 15 */
> +};
> +
> +
> +/*
> + * Conversion table from -3 to 55 degree Celcius
> + */
could use a single-line comment
> +static int therm_tbl[] = {
no twl4030_ prefix here
> +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
some indentation would be nice
> +};
> +
> +/*
> + * Structure containing the registers
> + * of different conversion methods supported by MADC.
> + * Hardware or RT real time conversion request initiated by external host
> + * processor for RT Signal conversions.
> + * External host processors can also request for non RT conversions
> + * SW1 and SW2 software conversions also called asynchronous or GPC request.
> + */
> +static
> +const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
> + [TWL4030_MADC_RT] = {
> + .sel = TWL4030_MADC_RTSELECT_LSB,
> + .avg = TWL4030_MADC_RTAVERAGE_LSB,
> + .rbase = TWL4030_MADC_RTCH0_LSB,
> + },
> + [TWL4030_MADC_SW1] = {
> + .sel = TWL4030_MADC_SW1SELECT_LSB,
> + .avg = TWL4030_MADC_SW1AVERAGE_LSB,
> + .rbase = TWL4030_MADC_GPCH0_LSB,
> + .ctrl = TWL4030_MADC_CTRL_SW1,
> + },
> + [TWL4030_MADC_SW2] = {
> + .sel = TWL4030_MADC_SW2SELECT_LSB,
> + .avg = TWL4030_MADC_SW2AVERAGE_LSB,
> + .rbase = TWL4030_MADC_GPCH0_LSB,
> + .ctrl = TWL4030_MADC_CTRL_SW2,
> + },
> +};
> +
> +/*
/**
> + * Function to read a particular channel value.
> + * @madc - pointer to struct twl4030_madc_data
> + * @reg - lsb of ADC Channel
> + * If the i2c read fails it returns an error else returns 0.
> + */
> +static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
> +{
> + u8 msb, lsb;
> + 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);
> + 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);
> + return ret;
> + }
could this be a word/u16 read? I haven't checked if there is autoincrement
support...
> +
> + return (int)(((msb << 8) | lsb) >> 6);
> +}
> +
> +/*
> + * Return battery temperature
stating the unit should nice
> + * Or < 0 on failure.
> + */
> +static int twl4030battery_temperature(int raw_volt)
> +{
> + u8 val;
> + int temp, curr, volt, res, ret;
> +
> + volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R;
> + /* Getting and calculating the supply current in micro ampers */
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];
> + if ((actual - res) >= 0)
> + break;
> + }
> +
> + return temp + 1;
> +}
> +
> +static int twl4030battery_current(int raw_volt)
> +{
> + int ret;
> + u8 val;
> +
> + ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
> + TWL4030_BCI_BCICTL1);
> + if (ret)
> + return ret;
> + if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */
> + return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1;
> + 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
> + * @buf - The channel values are stored here. if read fails error
> + * @raw - Return raw values without conversion
> + * value is stored
> + * Returns the number of successfully read channels.
> + */
> +static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
> + u8 reg_base, unsigned
> + long channels, int *buf,
> + bool raw)
> +{
> + int count = 0, i;
> +
> + for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) {
> + 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_base + 2 * i);
> + return buf[i];
> + }
> + if (raw) {
> + count++;
> + continue;
> + }
> + switch (i) {
> + case 10:
> + buf[i] = twl4030battery_current(buf[i]);
> + if (buf[i] < 0) {
> + dev_err(madc->dev, "err reading current\n");
> + return buf[i];
> + } else {
> + count++;
> + buf[i] = buf[i] - 750;
> + }
> + break;
> + case 1:
> + buf[i] = twl4030battery_temperature(buf[i]);
> + if (buf[i] < 0) {
> + dev_err(madc->dev, "err reading temperature\n");
> + return buf[i];
> + } else {
> + buf[i] -= 3;
> + count++;
> + }
> + break;
> + default:
> + count++;
> + /* Analog Input (V) = conv_result * step_size / R
> + * conv_result = decimal value of 10-bit conversion
> + * result
> + * step size = 1.5 / (2 ^ 10 -1)
> + * R = Prescaler ratio for input channels.
> + * Result given in mV hence multiplied by 1000.
> + */
> + buf[i] = (buf[i] * 3 * 1000 *
> + twl4030_divider_ratios[i].denominator)
> + / (2 * 1023 *
> + twl4030_divider_ratios[i].numerator);
> + }
> + }
> +
> + return count;
> +}
> +
> +/*
> + * Enables irq.
> + * @madc - pointer to twl4030_madc_data struct
> + * @id - irq number to be enabled
> + * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
> + * corresponding to RT, SW1, SW2 conversion requests.
> + * If the i2c read fails it returns an error else returns 0.
> + */
> +static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id)
> +{
> + u8 val;
> + int ret;
> +
> + ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
> + if (ret) {
> + dev_err(madc->dev, "unable to read imr register 0x%X\n",
> + 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;
> +}
> +
> +/*
> + * Disables irq.
> + * @madc - pointer to twl4030_madc_data struct
> + * @id - irq number to be disabled
> + * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
> + * corresponding to RT, SW1, SW2 conversion requests.
> + * Returns error if i2c read/write fails.
> + */
> +static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id)
> +{
> + u8 val;
> + int ret;
> +
> + ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
> + if (ret) {
> + dev_err(madc->dev, "unable to read imr register 0x%X\n",
> + 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;
> +}
> +
> +static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
> +{
> + struct twl4030_madc_data *madc = _madc;
> + const struct twl4030_madc_conversion_method *method;
> + u8 isr_val, imr_val;
> + int i, len, ret;
> + struct twl4030_madc_request *r;
> +
> + mutex_lock(&madc->lock);
> + ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr);
> + if (ret) {
> + dev_err(madc->dev, "unable to read isr register 0x%X\n",
> + madc->isr);
> + goto err_i2c;
> + }
> + ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr);
> + if (ret) {
> + dev_err(madc->dev, "unable to read imr register 0x%X\n",
> + madc->imr);
> + goto err_i2c;
> + }
> + isr_val &= ~imr_val;
> + for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
> + if (!(isr_val & (1 << i)))
> + continue;
> + ret = twl4030_madc_disable_irq(madc, i);
> + if (ret < 0)
> + dev_dbg(madc->dev, "Disable interrupt failed%d\n", i);
some space before %d
> + madc->requests[i].result_pending = 1;
> + }
> + for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
> + r = &madc->requests[i];
> + /* No pending results for this method, move to next one */
> + if (!r->result_pending)
> + continue;
> + method = &twl4030_conversion_methods[r->method];
> + /* Read results */
> + len = twl4030_madc_read_channels(madc, method->rbase,
> + r->channels, r->rbuf, r->raw);
> + /* Return results to caller */
> + if (r->func_cb != NULL) {
> + r->func_cb(len, r->channels, r->rbuf);
> + r->func_cb = NULL;
> + }
> + /* Free request */
> + r->result_pending = 0;
> + r->active = 0;
> + }
> + mutex_unlock(&madc->lock);
> +
> + return IRQ_HANDLED;
> +
> +err_i2c:
> + /*
> + * In case of error check whichever request is active
> + * and service the same.
> + */
> + for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
> + r = &madc->requests[i];
> + if (r->active == 0)
> + continue;
> + method = &twl4030_conversion_methods[r->method];
> + /* Read results */
> + len = twl4030_madc_read_channels(madc, method->rbase,
> + r->channels, r->rbuf, r->raw);
> + /* Return results to caller */
> + if (r->func_cb != NULL) {
> + r->func_cb(len, r->channels, r->rbuf);
> + r->func_cb = NULL;
> + }
> + /* Free request */
> + r->result_pending = 0;
> + r->active = 0;
> + }
> + mutex_unlock(&madc->lock);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
> + struct twl4030_madc_request *req)
> +{
> + struct twl4030_madc_request *p;
> + int ret;
> +
> + p = &madc->requests[req->method];
> + memcpy(p, req, sizeof(*req));
> + ret = twl4030_madc_enable_irq(madc, req->method);
> + if (ret < 0) {
> + dev_err(madc->dev, "enable irq failed!!\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * Function which enables the madc conversion
> + * by writing to the control register.
> + * @madc - pointer to twl4030_madc_data struct
> + * @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1
> + * corresponding to RT SW1 or SW2 conversion methods.
> + * Returns 0 if succeeds else a negative error value
> + */
> +static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
> + int conv_method)
> +{
> + 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];
> + 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;
> +}
> +
> +/*
> + * Function that waits for conversion to be ready
> + * @madc - pointer to twl4030_madc_data struct
> + * @timeout_ms - timeout value in milliseconds
> + * @status_reg - ctrl register
> + * returns 0 if succeeds else a negative error value
> + */
> +static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
> + unsigned int timeout_ms,
> + u8 status_reg)
> +{
> + unsigned long timeout;
> + int ret;
> +
> + timeout = jiffies + msecs_to_jiffies(timeout_ms);
> + do {
> + u8 reg;
> +
> + ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, ®, status_reg);
> + if (ret) {
> + dev_err(madc->dev,
> + "unable to read status register 0x%X\n",
> + status_reg);
> + return ret;
> + }
> + if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
> + return 0;
> + usleep_range(500, 2000);
> + } while (!time_after(jiffies, timeout));
> + dev_err(madc->dev, "conversion timeout!\n");
> +
> + return -EAGAIN;
> +}
> +
> +/*
> + * An exported function which can be called from other kernel drivers.
> + * @req twl4030_madc_request structure
> + * req->rbuf will be filled with read values of channels based on the
> + * channel index. If a particular channel reading fails there will
> + * be a negative error value in the corresponding array element.
> + * returns 0 if succeeds else error value
> + */
> +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)
> + return -EINVAL;
> +
> + mutex_lock(&twl4030_madc->lock);
> + if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
> + ret = -EINVAL;
> + goto out;
> + }
> + /* Do we have a conversion request ongoing */
> + if (twl4030_madc->requests[req->method].active) {
> + 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);
> + 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);
> + 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);
> + 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 sel reg 0x%X\n",
> + method->avg);
> + goto out;
> + }
> + }
> + if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) {
> + ret = twl4030_madc_set_irq(twl4030_madc, req);
> + if (ret < 0)
> + goto out;
> + ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
> + if (ret < 0)
> + goto out;
> + twl4030_madc->requests[req->method].active = 1;
> + ret = 0;
> + goto out;
> + }
> + /* With RT method we should not be here anymore */
> + if (req->method == TWL4030_MADC_RT) {
> + ret = -EINVAL;
> + goto out;
> + }
> + ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
> + if (ret < 0)
> + goto out;
> + twl4030_madc->requests[req->method].active = 1;
> + /* Wait until conversion is ready (ctrl register returns EOC) */
> + ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl);
> + if (ret) {
> + twl4030_madc->requests[req->method].active = 0;
> + goto out;
> + }
> + ret = twl4030_madc_read_channels(twl4030_madc, method->rbase,
> + req->channels, req->rbuf, req->raw);
> + twl4030_madc->requests[req->method].active = 0;
> +
> +out:
> + mutex_unlock(&twl4030_madc->lock);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(twl4030_madc_conversion);
> +
> +int twl4030_get_madc_conversion(int channel_no)
> +{
> + struct twl4030_madc_request req;
> + int temp = 0;
> + int ret;
> +
> + req.channels = (1 << channel_no);
> + req.method = TWL4030_MADC_SW2;
> + req.active = 0;
> + req.func_cb = NULL;
> + ret = twl4030_madc_conversion(&req);
> + if (ret < 0)
> + return ret;
> + if (req.rbuf[channel_no] > 0)
> + temp = req.rbuf[channel_no];
> +
> + return temp;
> +}
> +EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion);
> +
> +/*
> + * Function to enable or disable bias current for
> + * main battery type reading or temperature sensing
> + * @madc - pointer to twl4030_madc_data struct
> + * @chan - can be one of the two values
> + * TWL4030_BCI_ITHEN - Enables bias current for main battery type reading
> + * TWL4030_BCI_TYPEN - Enables bias current for main battery temperature
> + * sensing
> + * @on - enable or disable chan.
> + */
> +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,
> + ®val, TWL4030_BCI_BCICTL1);
> + if (ret) {
> + dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X",
> + TWL4030_BCI_BCICTL1);
> + return ret;
> + }
> +
> + regmask = (chan == 0) ? TWL4030_BCI_TYPEN : TWL4030_BCI_ITHEN;
> + if (on)
> + regval |= regmask;
> + else
> + regval &= ~regmask;
> +
> + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
> + regval, TWL4030_BCI_BCICTL1);
> + if (ret) {
> + dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n",
> + TWL4030_BCI_BCICTL1);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * 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.
power
> + * returns error if i2c read/write fails else 0
> + */
> +static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
> +{
> + u8 regval;
> + int ret;
> +
> + ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
> + ®val, TWL4030_MADC_CTRL1);
> + if (ret) {
> + dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n",
> + TWL4030_MADC_CTRL1);
> + return ret;
> + }
> + if (on)
> + regval |= TWL4030_MADC_MADCON;
> + else
> + regval &= ~TWL4030_MADC_MADCON;
> + ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1);
> + if (ret) {
> + dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n",
> + TWL4030_MADC_CTRL1);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * Initialize MADC and request for threaded irq
> + */
> +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 && !np) {
> + dev_err(&pdev->dev, "platform_data not available\n");
> + return -EINVAL;
> + }
> +
> + 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;
ARRAY_SIZE(twl4030_madc_iio_channels)
> +
> + /*
> + * 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.
> + */
> + 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 = (madc->use_second_irq == 1) ?
> + TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
> +
> + ret = twl4030_madc_set_power(madc, 1);
> + if (ret < 0)
> + return ret;
> + ret = twl4030_madc_set_current_generator(madc, 0, 1);
> + if (ret < 0)
> + goto err_current_generator;
> +
> + ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
> + ®val, TWL4030_BCI_BCICTL1);
> + if (ret) {
> + dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n",
> + TWL4030_BCI_BCICTL1);
> + goto err_i2c;
> + }
> + regval |= TWL4030_BCI_MESBAT;
> + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
> + regval, TWL4030_BCI_BCICTL1);
> + if (ret) {
> + dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n",
> + TWL4030_BCI_BCICTL1);
> + goto err_i2c;
> + }
> +
> + /* Check that MADC clock is on */
> + ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, ®val, TWL4030_REG_GPBR1);
> + if (ret) {
> + dev_err(&pdev->dev, "unable to read reg GPBR1 0x%X\n",
> + TWL4030_REG_GPBR1);
> + goto err_i2c;
> + }
> +
> + /* If MADC clk is not on, turn it on */
> + if (!(regval & TWL4030_GPBR1_MADC_HFCLK_EN)) {
> + dev_info(&pdev->dev, "clk disabled, enabling\n");
> + regval |= TWL4030_GPBR1_MADC_HFCLK_EN;
> + ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, regval,
> + TWL4030_REG_GPBR1);
> + if (ret) {
> + dev_err(&pdev->dev, "unable to write reg GPBR1 0x%X\n",
> + TWL4030_REG_GPBR1);
> + goto err_i2c;
> + }
> + }
> +
> + platform_set_drvdata(pdev, iio_dev);
> + mutex_init(&madc->lock);
> +
> + 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) {
> + dev_dbg(&pdev->dev, "could not request irq\n");
> + 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:
> + twl4030_madc_set_power(madc, 0);
> + return ret;
> +}
> +
> +static int twl4030_madc_remove(struct platform_device *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),
> + },
> +};
> +
> +module_platform_driver(twl4030_madc_driver);
> +
> +MODULE_DESCRIPTION("TWL4030 ADC driver");
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("J Keerthy");
> +MODULE_ALIAS("platform:twl4030_madc");
> 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
> diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
> deleted file mode 100644
> index 0bc79a7..0000000
> --- a/drivers/mfd/twl4030-madc.c
> +++ /dev/null
> @@ -1,914 +0,0 @@
> -/*
> - *
> - * TWL4030 MADC module driver-This driver monitors the real time
> - * conversion of analog signals like battery temperature,
> - * battery type, battery level etc.
> - *
> - * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
> - * J Keerthy <j-keerthy-l0cyMroinI0@public.gmane.org>
> - *
> - * Based on twl4030-madc.c
> - * Copyright (C) 2008 Nokia Corporation
> - * Mikko Ylinen <mikko.k.ylinen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
> - *
> - * Amit Kucheria <amit.kucheria-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
> - *
> - * This program is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU General Public License
> - * version 2 as published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope that it will be useful, but
> - * WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - * General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program; if not, write to the Free Software
> - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> - * 02110-1301 USA
> - *
> - */
> -
> -#include <linux/init.h>
> -#include <linux/device.h>
> -#include <linux/interrupt.h>
> -#include <linux/kernel.h>
> -#include <linux/delay.h>
> -#include <linux/platform_device.h>
> -#include <linux/slab.h>
> -#include <linux/i2c/twl.h>
> -#include <linux/i2c/twl4030-madc.h>
> -#include <linux/module.h>
> -#include <linux/stddef.h>
> -#include <linux/mutex.h>
> -#include <linux/bitops.h>
> -#include <linux/jiffies.h>
> -#include <linux/types.h>
> -#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
> - * @lock - mutex protecting this data structure
> - * @requests - Array of request struct corresponding to SW1, SW2 and RT
> - * @imr - Interrupt mask register of MADC
> - * @isr - Interrupt status register of MADC
> - */
> -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;
> - u8 imr;
> - u8 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 = 0;
> - req.func_cb = NULL;
> - 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 {
> - s16 numerator;
> - s16 denominator;
> -};
> -
> -static const struct twl4030_prescale_divider_ratios
> -twl4030_divider_ratios[16] = {
> - {1, 1}, /* CHANNEL 0 No Prescaler */
> - {1, 1}, /* CHANNEL 1 No Prescaler */
> - {6, 10}, /* CHANNEL 2 */
> - {6, 10}, /* CHANNEL 3 */
> - {6, 10}, /* CHANNEL 4 */
> - {6, 10}, /* CHANNEL 5 */
> - {6, 10}, /* CHANNEL 6 */
> - {6, 10}, /* CHANNEL 7 */
> - {3, 14}, /* CHANNEL 8 */
> - {1, 3}, /* CHANNEL 9 */
> - {1, 1}, /* CHANNEL 10 No Prescaler */
> - {15, 100}, /* CHANNEL 11 */
> - {1, 4}, /* CHANNEL 12 */
> - {1, 1}, /* CHANNEL 13 Reserved channels */
> - {1, 1}, /* CHANNEL 14 Reseved channels */
> - {5, 11}, /* CHANNEL 15 */
> -};
> -
> -
> -/*
> - * 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
> -};
> -
> -/*
> - * Structure containing the registers
> - * of different conversion methods supported by MADC.
> - * Hardware or RT real time conversion request initiated by external host
> - * processor for RT Signal conversions.
> - * External host processors can also request for non RT conversions
> - * SW1 and SW2 software conversions also called asynchronous or GPC request.
> - */
> -static
> -const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
> - [TWL4030_MADC_RT] = {
> - .sel = TWL4030_MADC_RTSELECT_LSB,
> - .avg = TWL4030_MADC_RTAVERAGE_LSB,
> - .rbase = TWL4030_MADC_RTCH0_LSB,
> - },
> - [TWL4030_MADC_SW1] = {
> - .sel = TWL4030_MADC_SW1SELECT_LSB,
> - .avg = TWL4030_MADC_SW1AVERAGE_LSB,
> - .rbase = TWL4030_MADC_GPCH0_LSB,
> - .ctrl = TWL4030_MADC_CTRL_SW1,
> - },
> - [TWL4030_MADC_SW2] = {
> - .sel = TWL4030_MADC_SW2SELECT_LSB,
> - .avg = TWL4030_MADC_SW2AVERAGE_LSB,
> - .rbase = TWL4030_MADC_GPCH0_LSB,
> - .ctrl = TWL4030_MADC_CTRL_SW2,
> - },
> -};
> -
> -/*
> - * Function to read a particular channel value.
> - * @madc - pointer to struct twl4030_madc_data
> - * @reg - lsb of ADC Channel
> - * If the i2c read fails it returns an error else returns 0.
> - */
> -static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
> -{
> - u8 msb, lsb;
> - 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);
> - 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);
> - return ret;
> - }
> -
> - return (int)(((msb << 8) | lsb) >> 6);
> -}
> -
> -/*
> - * Return battery temperature
> - * Or < 0 on failure.
> - */
> -static int twl4030battery_temperature(int raw_volt)
> -{
> - u8 val;
> - int temp, curr, volt, res, ret;
> -
> - volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R;
> - /* Getting and calculating the supply current in micro ampers */
> - 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];
> - if ((actual - res) >= 0)
> - break;
> - }
> -
> - return temp + 1;
> -}
> -
> -static int twl4030battery_current(int raw_volt)
> -{
> - int ret;
> - u8 val;
> -
> - ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
> - TWL4030_BCI_BCICTL1);
> - if (ret)
> - return ret;
> - if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */
> - return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1;
> - 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
> - * @buf - The channel values are stored here. if read fails error
> - * @raw - Return raw values without conversion
> - * value is stored
> - * Returns the number of successfully read channels.
> - */
> -static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
> - u8 reg_base, unsigned
> - long channels, int *buf,
> - bool raw)
> -{
> - int count = 0, i;
> -
> - for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) {
> - 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_base + 2 * i);
> - return buf[i];
> - }
> - if (raw) {
> - count++;
> - continue;
> - }
> - switch (i) {
> - case 10:
> - buf[i] = twl4030battery_current(buf[i]);
> - if (buf[i] < 0) {
> - dev_err(madc->dev, "err reading current\n");
> - return buf[i];
> - } else {
> - count++;
> - buf[i] = buf[i] - 750;
> - }
> - break;
> - case 1:
> - buf[i] = twl4030battery_temperature(buf[i]);
> - if (buf[i] < 0) {
> - dev_err(madc->dev, "err reading temperature\n");
> - return buf[i];
> - } else {
> - buf[i] -= 3;
> - count++;
> - }
> - break;
> - default:
> - count++;
> - /* Analog Input (V) = conv_result * step_size / R
> - * conv_result = decimal value of 10-bit conversion
> - * result
> - * step size = 1.5 / (2 ^ 10 -1)
> - * R = Prescaler ratio for input channels.
> - * Result given in mV hence multiplied by 1000.
> - */
> - buf[i] = (buf[i] * 3 * 1000 *
> - twl4030_divider_ratios[i].denominator)
> - / (2 * 1023 *
> - twl4030_divider_ratios[i].numerator);
> - }
> - }
> -
> - return count;
> -}
> -
> -/*
> - * Enables irq.
> - * @madc - pointer to twl4030_madc_data struct
> - * @id - irq number to be enabled
> - * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
> - * corresponding to RT, SW1, SW2 conversion requests.
> - * If the i2c read fails it returns an error else returns 0.
> - */
> -static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id)
> -{
> - u8 val;
> - int ret;
> -
> - ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
> - if (ret) {
> - dev_err(madc->dev, "unable to read imr register 0x%X\n",
> - 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;
> -}
> -
> -/*
> - * Disables irq.
> - * @madc - pointer to twl4030_madc_data struct
> - * @id - irq number to be disabled
> - * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
> - * corresponding to RT, SW1, SW2 conversion requests.
> - * Returns error if i2c read/write fails.
> - */
> -static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id)
> -{
> - u8 val;
> - int ret;
> -
> - ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
> - if (ret) {
> - dev_err(madc->dev, "unable to read imr register 0x%X\n",
> - 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;
> -}
> -
> -static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
> -{
> - struct twl4030_madc_data *madc = _madc;
> - const struct twl4030_madc_conversion_method *method;
> - u8 isr_val, imr_val;
> - int i, len, ret;
> - struct twl4030_madc_request *r;
> -
> - mutex_lock(&madc->lock);
> - ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr);
> - if (ret) {
> - dev_err(madc->dev, "unable to read isr register 0x%X\n",
> - madc->isr);
> - goto err_i2c;
> - }
> - ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr);
> - if (ret) {
> - dev_err(madc->dev, "unable to read imr register 0x%X\n",
> - madc->imr);
> - goto err_i2c;
> - }
> - isr_val &= ~imr_val;
> - for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
> - if (!(isr_val & (1 << i)))
> - continue;
> - ret = twl4030_madc_disable_irq(madc, i);
> - if (ret < 0)
> - 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++) {
> - r = &madc->requests[i];
> - /* No pending results for this method, move to next one */
> - if (!r->result_pending)
> - continue;
> - method = &twl4030_conversion_methods[r->method];
> - /* Read results */
> - len = twl4030_madc_read_channels(madc, method->rbase,
> - r->channels, r->rbuf, r->raw);
> - /* Return results to caller */
> - if (r->func_cb != NULL) {
> - r->func_cb(len, r->channels, r->rbuf);
> - r->func_cb = NULL;
> - }
> - /* Free request */
> - r->result_pending = 0;
> - r->active = 0;
> - }
> - mutex_unlock(&madc->lock);
> -
> - return IRQ_HANDLED;
> -
> -err_i2c:
> - /*
> - * In case of error check whichever request is active
> - * and service the same.
> - */
> - for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
> - r = &madc->requests[i];
> - if (r->active == 0)
> - continue;
> - method = &twl4030_conversion_methods[r->method];
> - /* Read results */
> - len = twl4030_madc_read_channels(madc, method->rbase,
> - r->channels, r->rbuf, r->raw);
> - /* Return results to caller */
> - if (r->func_cb != NULL) {
> - r->func_cb(len, r->channels, r->rbuf);
> - r->func_cb = NULL;
> - }
> - /* Free request */
> - r->result_pending = 0;
> - r->active = 0;
> - }
> - mutex_unlock(&madc->lock);
> -
> - return IRQ_HANDLED;
> -}
> -
> -static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
> - struct twl4030_madc_request *req)
> -{
> - struct twl4030_madc_request *p;
> - int ret;
> -
> - p = &madc->requests[req->method];
> - memcpy(p, req, sizeof(*req));
> - ret = twl4030_madc_enable_irq(madc, req->method);
> - if (ret < 0) {
> - dev_err(madc->dev, "enable irq failed!!\n");
> - return ret;
> - }
> -
> - return 0;
> -}
> -
> -/*
> - * Function which enables the madc conversion
> - * by writing to the control register.
> - * @madc - pointer to twl4030_madc_data struct
> - * @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1
> - * corresponding to RT SW1 or SW2 conversion methods.
> - * Returns 0 if succeeds else a negative error value
> - */
> -static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
> - int conv_method)
> -{
> - 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];
> - 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;
> -}
> -
> -/*
> - * Function that waits for conversion to be ready
> - * @madc - pointer to twl4030_madc_data struct
> - * @timeout_ms - timeout value in milliseconds
> - * @status_reg - ctrl register
> - * returns 0 if succeeds else a negative error value
> - */
> -static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
> - unsigned int timeout_ms,
> - u8 status_reg)
> -{
> - unsigned long timeout;
> - int ret;
> -
> - timeout = jiffies + msecs_to_jiffies(timeout_ms);
> - do {
> - u8 reg;
> -
> - ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, ®, status_reg);
> - if (ret) {
> - dev_err(madc->dev,
> - "unable to read status register 0x%X\n",
> - status_reg);
> - return ret;
> - }
> - if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
> - return 0;
> - usleep_range(500, 2000);
> - } while (!time_after(jiffies, timeout));
> - dev_err(madc->dev, "conversion timeout!\n");
> -
> - return -EAGAIN;
> -}
> -
> -/*
> - * An exported function which can be called from other kernel drivers.
> - * @req twl4030_madc_request structure
> - * req->rbuf will be filled with read values of channels based on the
> - * channel index. If a particular channel reading fails there will
> - * be a negative error value in the corresponding array element.
> - * returns 0 if succeeds else error value
> - */
> -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)
> - return -EINVAL;
> -
> - mutex_lock(&twl4030_madc->lock);
> - if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
> - ret = -EINVAL;
> - goto out;
> - }
> - /* Do we have a conversion request ongoing */
> - if (twl4030_madc->requests[req->method].active) {
> - 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);
> - 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);
> - 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);
> - 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 sel reg 0x%X\n",
> - method->avg);
> - goto out;
> - }
> - }
> - if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) {
> - ret = twl4030_madc_set_irq(twl4030_madc, req);
> - if (ret < 0)
> - goto out;
> - ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
> - if (ret < 0)
> - goto out;
> - twl4030_madc->requests[req->method].active = 1;
> - ret = 0;
> - goto out;
> - }
> - /* With RT method we should not be here anymore */
> - if (req->method == TWL4030_MADC_RT) {
> - ret = -EINVAL;
> - goto out;
> - }
> - ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
> - if (ret < 0)
> - goto out;
> - twl4030_madc->requests[req->method].active = 1;
> - /* Wait until conversion is ready (ctrl register returns EOC) */
> - ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl);
> - if (ret) {
> - twl4030_madc->requests[req->method].active = 0;
> - goto out;
> - }
> - ret = twl4030_madc_read_channels(twl4030_madc, method->rbase,
> - req->channels, req->rbuf, req->raw);
> - twl4030_madc->requests[req->method].active = 0;
> -
> -out:
> - mutex_unlock(&twl4030_madc->lock);
> -
> - return ret;
> -}
> -EXPORT_SYMBOL_GPL(twl4030_madc_conversion);
> -
> -int twl4030_get_madc_conversion(int channel_no)
> -{
> - struct twl4030_madc_request req;
> - int temp = 0;
> - int ret;
> -
> - req.channels = (1 << channel_no);
> - req.method = TWL4030_MADC_SW2;
> - req.active = 0;
> - req.func_cb = NULL;
> - ret = twl4030_madc_conversion(&req);
> - if (ret < 0)
> - return ret;
> - if (req.rbuf[channel_no] > 0)
> - temp = req.rbuf[channel_no];
> -
> - return temp;
> -}
> -EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion);
> -
> -/*
> - * Function to enable or disable bias current for
> - * main battery type reading or temperature sensing
> - * @madc - pointer to twl4030_madc_data struct
> - * @chan - can be one of the two values
> - * TWL4030_BCI_ITHEN - Enables bias current for main battery type reading
> - * TWL4030_BCI_TYPEN - Enables bias current for main battery temperature
> - * sensing
> - * @on - enable or disable chan.
> - */
> -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,
> - ®val, TWL4030_BCI_BCICTL1);
> - if (ret) {
> - dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X",
> - TWL4030_BCI_BCICTL1);
> - return ret;
> - }
> -
> - regmask = (chan == 0) ? TWL4030_BCI_TYPEN : TWL4030_BCI_ITHEN;
> - if (on)
> - regval |= regmask;
> - else
> - regval &= ~regmask;
> -
> - ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
> - regval, TWL4030_BCI_BCICTL1);
> - if (ret) {
> - dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n",
> - TWL4030_BCI_BCICTL1);
> - return ret;
> - }
> -
> - return 0;
> -}
> -
> -/*
> - * 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.
> - * returns error if i2c read/write fails else 0
> - */
> -static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
> -{
> - u8 regval;
> - int ret;
> -
> - ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
> - ®val, TWL4030_MADC_CTRL1);
> - if (ret) {
> - dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n",
> - TWL4030_MADC_CTRL1);
> - return ret;
> - }
> - if (on)
> - regval |= TWL4030_MADC_MADCON;
> - else
> - regval &= ~TWL4030_MADC_MADCON;
> - ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1);
> - if (ret) {
> - dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n",
> - TWL4030_MADC_CTRL1);
> - return ret;
> - }
> -
> - return 0;
> -}
> -
> -/*
> - * Initialize MADC and request for threaded irq
> - */
> -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 && !np) {
> - dev_err(&pdev->dev, "platform_data not available\n");
> - return -EINVAL;
> - }
> -
> - 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.
> - */
> - 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 = (madc->use_second_irq == 1) ?
> - TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
> -
> - ret = twl4030_madc_set_power(madc, 1);
> - if (ret < 0)
> - return ret;
> - ret = twl4030_madc_set_current_generator(madc, 0, 1);
> - if (ret < 0)
> - goto err_current_generator;
> -
> - ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
> - ®val, TWL4030_BCI_BCICTL1);
> - if (ret) {
> - dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n",
> - TWL4030_BCI_BCICTL1);
> - goto err_i2c;
> - }
> - regval |= TWL4030_BCI_MESBAT;
> - ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
> - regval, TWL4030_BCI_BCICTL1);
> - if (ret) {
> - dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n",
> - TWL4030_BCI_BCICTL1);
> - goto err_i2c;
> - }
> -
> - /* Check that MADC clock is on */
> - ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, ®val, TWL4030_REG_GPBR1);
> - if (ret) {
> - dev_err(&pdev->dev, "unable to read reg GPBR1 0x%X\n",
> - TWL4030_REG_GPBR1);
> - goto err_i2c;
> - }
> -
> - /* If MADC clk is not on, turn it on */
> - if (!(regval & TWL4030_GPBR1_MADC_HFCLK_EN)) {
> - dev_info(&pdev->dev, "clk disabled, enabling\n");
> - regval |= TWL4030_GPBR1_MADC_HFCLK_EN;
> - ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, regval,
> - TWL4030_REG_GPBR1);
> - if (ret) {
> - dev_err(&pdev->dev, "unable to write reg GPBR1 0x%X\n",
> - TWL4030_REG_GPBR1);
> - goto err_i2c;
> - }
> - }
> -
> - platform_set_drvdata(pdev, iio_dev);
> - mutex_init(&madc->lock);
> -
> - 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) {
> - dev_dbg(&pdev->dev, "could not request irq\n");
> - 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:
> - twl4030_madc_set_power(madc, 0);
> - return ret;
> -}
> -
> -static int twl4030_madc_remove(struct platform_device *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),
> - },
> -};
> -
> -module_platform_driver(twl4030_madc_driver);
> -
> -MODULE_DESCRIPTION("TWL4030 ADC driver");
> -MODULE_LICENSE("GPL");
> -MODULE_AUTHOR("J Keerthy");
> -MODULE_ALIAS("platform:twl4030_madc");
>
--
Peter Meerwald
+43-664-2444418 (mobile)
^ permalink raw reply
* Re: [PATCH v7 13/15] ARM: sun4i: dt: Remove grouping + simple-bus compatible for regulators
From: Maxime Ripard @ 2014-02-24 9:14 UTC (permalink / raw)
To: Hans de Goede
Cc: Tejun Heo, Oliver Schinagl, Richard Zhu, Roger Quadros, Lee Jones,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
In-Reply-To: <5309AB64.7010603-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 574 bytes --]
On Sun, Feb 23, 2014 at 09:03:48AM +0100, Hans de Goede wrote:
> Thanks, I assume this only applies to this patch, since we were still
> discussing the common regulator bits of the ahci enablement dts patches ?
Yes.
> I'm not seeing any of your recent merges here:
> https://github.com/mripard/linux/commits/sunxi/dt-for-3.15
>
> Did you not push them, or am I looking at the wrong tree ?
I forgot to push it. It's fixed now.
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH v2] dt/bindings: fsl-fec: add clock properties
From: Gerhard Sittig @ 2014-02-24 8:51 UTC (permalink / raw)
To: Shawn Guo
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Mark Rutland,
Philippe De Muyter
In-Reply-To: <1393206490-25234-1-git-send-email-shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
On Mon, Feb 24, 2014 at 09:48 +0800, Shawn Guo wrote:
>
> Update fsl-fec.txt to add 'clocks' and 'clock-names' properties.
>
> Signed-off-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
> Changes since v1:
> - Leave compatible change out, which should probably be addressed by
> another patch
> - Move clock properties into 'Optional properties:' section
>
> Documentation/devicetree/bindings/net/fsl-fec.txt | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt
> index 845ff84..468736d 100644
> --- a/Documentation/devicetree/bindings/net/fsl-fec.txt
> +++ b/Documentation/devicetree/bindings/net/fsl-fec.txt
> @@ -16,6 +16,15 @@ Optional properties:
> will have the duration be 1 millisecond. Numbers greater than 1000 are
> invalid and 1 millisecond will be used instead.
> - phy-supply: regulator that powers the Ethernet PHY.
> +- clocks: the clocks feeding the FEC controller and phy.
> + - "ipg": the peripheral access clock
> + - "ahb": the bus clock for MAC
> + - "ptp": the sampling clock for PTP (IEEE 1588). On SoC like i.MX6Q,
> + the clock could come from either the internal clock control module
> + or external oscillator via pad depending on board design.
> + - "enet_out": the phy reference clock provided by SoC via pad, which
> + is available on SoC like i.MX28.
> +- clock-names: Must contain the clock names described just above
>
> Example:
I can agree with that change. It improves the situation for i.MX
(provides missing information for ARM), and doesn't break MPC,
while I'm not aware of other FEC (fast ethernet controller) uses.
For MPC though, I will have to provide a followup.
Starting with v3.12 (2771399a "fs_enet: cleanup clock API use")
the Linux drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
implementation looks up the "per" clock, while failure isn't
fatal. I will change this to lookup "ipg" first and fallback to
"per" then. Up to and including v3.13 no PowerPC .dts file
provides clock specs for FEC nodes, so lookup always fails. I'm
guilty of not having provided a bindings update back then.
Starting with v3.14-rc1 the MPC5121/23/25 platform does provide
proper COMMON_CLK support, but comes with full backwards compat
support, too. So failure to lookup the clock spec still isn't
fatal, the code works with both updated as well as pre-existing
device trees. And it will keep working across "incompatible"
changes in the .dts, switching from "per" to "ipg" names for the
FEC nodes.
So there are three changes that I will have to prepare:
- documenting "per" as an (obsolete) alias for "ipg" in the
binding
- looking up "ipg" before "per" in one of the FEC drivers
- and switching from "per" to "ipg" in MPC .dts files
As outlined above, none of these changes depends on a specific
order, nothing needs to get rushed into v3.14, although it would
be nice to start shipping with a consistent state.
virtually yours
Gerhard Sittig
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr. 5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office-ynQEQJNshbs@public.gmane.org
--
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
* [PATCH 04/10] ARM: dove: add global-config register node
From: Sebastian Hesselbarth @ 2014-02-24 8:42 UTC (permalink / raw)
To: Sebastian Hesselbarth
Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
Rob Landley, Linus Walleij, Russell King, Jason Cooper,
Andrew Lunn, Gregory Clement, devicetree, linux-doc,
linux-arm-kernel, linux-kernel
In-Reply-To: <1393231382-11078-1-git-send-email-sebastian.hesselbarth@gmail.com>
We share global config registers by syscon node, add it to dove.dtsi.
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Rob Landley <rob@landley.net>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Gregory Clement <gregory.clement@free-electrons.com>
Cc: devicetree@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
arch/arm/boot/dts/dove.dtsi | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi
index c5e90f0287b9..eeb08edb67ac 100644
--- a/arch/arm/boot/dts/dove.dtsi
+++ b/arch/arm/boot/dts/dove.dtsi
@@ -616,6 +616,12 @@
interrupts = <5>;
};
+ gconf: global-config@e802c {
+ compatible = "marvell,dove-global-config",
+ "syscon";
+ reg = <0xe802c 0x14>;
+ };
+
gpio2: gpio-ctrl@e8400 {
compatible = "marvell,orion-gpio";
#gpio-cells = <2>;
--
1.8.5.3
^ permalink raw reply related
* [PATCH 03/10] ARM: dove: add additional pinctrl registers
From: Sebastian Hesselbarth @ 2014-02-24 8:42 UTC (permalink / raw)
To: Sebastian Hesselbarth
Cc: Mark Rutland, Andrew Lunn, Russell King, Jason Cooper, Pawel Moll,
Ian Campbell, Linus Walleij, linux-doc, linux-kernel, devicetree,
Rob Herring, Rob Landley, Kumar Gala, Gregory Clement,
linux-arm-kernel
In-Reply-To: <1393231382-11078-1-git-send-email-sebastian.hesselbarth@gmail.com>
Dove pinctrl uses additional registers to control MPPs. This patch first
increases existing pinctrl reg property by one register, and then adds
two new ranges for MPP4 and PMU MPP registers.
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Rob Landley <rob@landley.net>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Gregory Clement <gregory.clement@free-electrons.com>
Cc: devicetree@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
arch/arm/boot/dts/dove.dtsi | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi
index 2b76524f4aa7..c5e90f0287b9 100644
--- a/arch/arm/boot/dts/dove.dtsi
+++ b/arch/arm/boot/dts/dove.dtsi
@@ -390,7 +390,9 @@
pinctrl: pin-ctrl@d0200 {
compatible = "marvell,dove-pinctrl";
- reg = <0xd0200 0x10>;
+ reg = <0xd0200 0x14>,
+ <0xd0440 0x04>,
+ <0xd802c 0x08>;
clocks = <&gate_clk 22>;
pmx_gpio_0: pmx-gpio-0 {
--
1.8.5.3
^ permalink raw reply related
* [PATCH 02/10] devicetree: bindings: update MVEBU pinctrl binding documentation
From: Sebastian Hesselbarth @ 2014-02-24 8:42 UTC (permalink / raw)
To: Sebastian Hesselbarth
Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
Rob Landley, Linus Walleij, Jason Cooper, Andrew Lunn,
Gregory Clement, devicetree, linux-doc, linux-arm-kernel,
linux-kernel
In-Reply-To: <1393231382-11078-1-git-send-email-sebastian.hesselbarth@gmail.com>
Dove pinctrl binding now requires three different reg properties. This
updates corresponding binding and example accordingly. While at it, also
document reg property as required for the other MVEBU SoC pinctrl nodes.
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Rob Landley <rob@landley.net>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Gregory Clement <gregory.clement@free-electrons.com>
Cc: devicetree@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
.../devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt | 1 +
.../devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt | 1 +
.../devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt | 1 +
Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt | 1 +
Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt | 1 +
Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt | 1 +
Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt | 2 +-
7 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt
index 01ef408e205f..adda2a8d1d52 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-370-pinctrl.txt
@@ -5,6 +5,7 @@ part and usage.
Required properties:
- compatible: "marvell,88f6710-pinctrl"
+- reg: register specifier of MPP registers
Available mpp pins/groups and functions:
Note: brackets (x) are not part of the mpp name for marvell,function and given
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt
index 2ede59dffe1b..7de0cda4a379 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-375-pinctrl.txt
@@ -5,6 +5,7 @@ part and usage.
Required properties:
- compatible: "marvell,88f6720-pinctrl"
+- reg: register specifier of MPP registers
Available mpp pins/groups and functions:
Note: brackets (x) are not part of the mpp name for marvell,function and given
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt
index 1d45f9d62346..b17c96849fc9 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-38x-pinctrl.txt
@@ -7,6 +7,7 @@ Required properties:
- compatible: "marvell,88f6810-pinctrl", "marvell,88f6820-pinctrl" or
"marvell,88f6828-pinctrl" depending on the specific variant of the
SoC being used.
+- reg: register specifier of MPP registers
Available mpp pins/groups and functions:
Note: brackets (x) are not part of the mpp name for marvell,function and given
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt
index bfa0a2e5e0cb..373dbccd7ab0 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-xp-pinctrl.txt
@@ -6,6 +6,7 @@ part and usage.
Required properties:
- compatible: "marvell,mv78230-pinctrl", "marvell,mv78260-pinctrl",
"marvell,mv78460-pinctrl"
+- reg: register specifier of MPP registers
This driver supports all Armada XP variants, i.e. mv78230, mv78260, and mv78460.
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt
index 50ec3512a292..cf52477cc7ee 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt
@@ -6,6 +6,7 @@ part and usage.
Required properties:
- compatible: "marvell,dove-pinctrl"
- clocks: (optional) phandle of pdma clock
+- reg: register specifiers of MPP, MPP4, and PMU MPP registers
Available mpp pins/groups and functions:
Note: brackets (x) are not part of the mpp name for marvell,function and given
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt
index 95daf6335c37..730444a9a4de 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt
@@ -8,6 +8,7 @@ Required properties:
"marvell,88f6190-pinctrl", "marvell,88f6192-pinctrl",
"marvell,88f6281-pinctrl", "marvell,88f6282-pinctrl"
"marvell,98dx4122-pinctrl"
+- reg: register specifier of MPP registers
This driver supports all kirkwood variants, i.e. 88f6180, 88f619x, and 88f628x.
It also support the 88f6281-based variant in the 98dx412x Bobcat SoCs.
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt
index 0a26c3aa4e6d..0c09f4eb2af0 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt
@@ -37,7 +37,7 @@ uart1: serial@12100 {
pinctrl: pinctrl@d0200 {
compatible = "marvell,dove-pinctrl";
- reg = <0xd0200 0x20>;
+ reg = <0xd0200 0x14>, <0xd0440 0x04>, <0xd802c 0x08>;
pmx_uart1_sw: pmx-uart1-sw {
marvell,pins = "mpp_uart1";
--
1.8.5.3
^ permalink raw reply related
* [PATCH 01/10] devicetree: bindings: add missing Marvell Dove SoC documentation
From: Sebastian Hesselbarth @ 2014-02-24 8:42 UTC (permalink / raw)
To: Sebastian Hesselbarth
Cc: Mark Rutland, Andrew Lunn, Jason Cooper, Pawel Moll, Ian Campbell,
Linus Walleij, linux-doc, linux-kernel, devicetree, Rob Herring,
Rob Landley, Kumar Gala, Gregory Clement, linux-arm-kernel
In-Reply-To: <1393231382-11078-1-git-send-email-sebastian.hesselbarth@gmail.com>
Marvell Dove SoC binding was not documented, yet. Add the documentation
and also describe Global Configuration register node in it.
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
---
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Rob Landley <rob@landley.net>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Gregory Clement <gregory.clement@free-electrons.com>
Cc: devicetree@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
---
.../devicetree/bindings/arm/marvell,dove.txt | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/marvell,dove.txt
diff --git a/Documentation/devicetree/bindings/arm/marvell,dove.txt b/Documentation/devicetree/bindings/arm/marvell,dove.txt
new file mode 100644
index 000000000000..aaaf64c56e44
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/marvell,dove.txt
@@ -0,0 +1,22 @@
+Marvell Dove Platforms Device Tree Bindings
+-----------------------------------------------
+
+Boards with a Marvell Dove SoC shall have the following properties:
+
+Required root node property:
+- compatible: must contain "marvell,dove";
+
+* Global Configuration registers
+
+Global Configuration registers of Dove SoC are shared by a syscon node.
+
+Required properties:
+- compatible: must contain "marvell,dove-global-config" and "syscon".
+- reg: base address and size of the Global Configuration registers.
+
+Example:
+
+gconf: global-config@e802c {
+ compatible = "marvell,dove-global-config", "syscon";
+ reg = <0xe802c 0x14>;
+};
--
1.8.5.3
^ permalink raw reply related
* [PATCH 00/10] pinctrl: mvebu: remove hard-coded addresses from Dove pinctrl
From: Sebastian Hesselbarth @ 2014-02-24 8:42 UTC (permalink / raw)
To: Sebastian Hesselbarth
Cc: Mark Rutland, Andrew Lunn, Russell King, Jason Cooper, Pawel Moll,
Ian Campbell, Linus Walleij, linux-doc, linux-kernel, devicetree,
Rob Herring, Rob Landley, Kumar Gala, Gregory Clement,
linux-arm-kernel
This is a patches separated from one sent earlier [1] with just the
removal of any hard-coded reg addresses from Dove pinctrl stub. This
is a required step for Dove to leave mach-dove, hop into mach-mvebu,
and become part of multi_v7.
In the meantime, support for new Armada 375/38x was added that also
contain patches for pinctrl [2]. The cleanup patches [3] split off from
the original patch set take care of pinctrl-related changes for Armada
375/38x. Since this patch set now already depends on Armada 375/38x
pinctrl through those cleanup patches, we take care of Armada 375/38x
binding updates here, too.
For Dove, this patch set removes all hardcoded addresses from
pinctrl-dove by either requesting additional resources or a syscon
provided regmap for global config registers. As this changes existing
driver to DT binding relationship, all additional resources are probed
in a backward compatible way. If the corresponding resource cannot be
found, we derive it from the existing pinctrl resource and warn about
the old DTB firmware.
Patches 1-2 add or update binding documentation for dove, global config
syscon, and pinctrl-dove. Patch 2 also documents missing reg property
requirement for other mvebu pinctrl nodes, including new Armada 375/38x.
Patch 3 and 4 add the new pinctrl reg property values and global config
register syscon to exisiting dove.dtsi.
Patches 5-6 request either additional reg ranges or the syscon regmap
in a DT-backward compatible way. If any resource cannot be derived from
DT node, we warn about an old DTB firmware.
Patches 7-10 finally remove any hardcoded addresses from Dove SoC
pinctrl driver and use the iomap/regmap resources instead.
DT and binding related patches have also been sent to DT maintainers
and corresponding lists, additional pinctrl related patches have been
sent to pinctrl/mvebu maintainers and LAKML only.
This patch set is based on v3.14-rc1 and depends on some cleanup patches
that will go into v3.15. We have a lot of stuff for v3.15 already in
mvebu, so I am okay with postponing this and/or the following dove-to-
mvebu patches for v3.16. As Jason prepares mvebu pinctrl PRs for LinusW,
it is up to him when to take it with LinusW's Acked-by.
Nevertheless, there is an *unstable* branch based on v3.14-rc1, with
mvebu/pinctrl-3xx and mvebu/pinctrl merged in at (still named -for-3.15)
https://github.com/shesselba/linux-dove.git unstable/dove-pinctrl-for-3.15_v1
[1] http://www.spinics.net/lists/arm-kernel/msg303496.html
[2] http://www.spinics.net/lists/arm-kernel/msg306409.html
[3] http://lkml.org/lkml/2014/2/23/43
Sebastian Hesselbarth (10):
devicetree: bindings: add missing Marvell Dove SoC documentation
devicetree: bindings: update MVEBU pinctrl binding documentation
ARM: dove: add additional pinctrl registers
ARM: dove: add global-config register node
pinctrl: mvebu: dove: request additional resources
pinctrl: mvebu: dove: request syscon regmap for global registers
pinctrl: mvebu: dove: use remapped mpp base registers
pinctrl: mvebu: dove: use remapped mpp4 register
pinctrl: mvebu: dove: use remapped pmu_mpp registers
pinctrl: mvebu: dove: use global register regmap
.../devicetree/bindings/arm/marvell,dove.txt | 22 ++
.../pinctrl/marvell,armada-370-pinctrl.txt | 1 +
.../pinctrl/marvell,armada-375-pinctrl.txt | 1 +
.../pinctrl/marvell,armada-38x-pinctrl.txt | 1 +
.../bindings/pinctrl/marvell,armada-xp-pinctrl.txt | 1 +
.../bindings/pinctrl/marvell,dove-pinctrl.txt | 1 +
.../bindings/pinctrl/marvell,kirkwood-pinctrl.txt | 1 +
.../bindings/pinctrl/marvell,mvebu-pinctrl.txt | 2 +-
arch/arm/boot/dts/dove.dtsi | 10 +-
drivers/pinctrl/mvebu/Kconfig | 1 +
drivers/pinctrl/mvebu/pinctrl-dove.c | 286 +++++++++++++--------
11 files changed, 213 insertions(+), 114 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/marvell,dove.txt
---
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Rob Landley <rob@landley.net>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Gregory Clement <gregory.clement@free-electrons.com>
Cc: devicetree@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
--
1.8.5.3
^ permalink raw reply
* Re: [PATCH v2] dt/bindings: fsl-fec: add clock properties
From: Shawn Guo @ 2014-02-24 8:34 UTC (permalink / raw)
To: Sascha Hauer
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Mark Rutland,
Gerhard Sittig, Philippe De Muyter
In-Reply-To: <20140224075337.GN17250-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
On Mon, Feb 24, 2014 at 08:53:37AM +0100, Sascha Hauer wrote:
> On Mon, Feb 24, 2014 at 09:48:10AM +0800, Shawn Guo wrote:
> > Update fsl-fec.txt to add 'clocks' and 'clock-names' properties.
> >
> > Signed-off-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> > ---
> > Changes since v1:
> > - Leave compatible change out, which should probably be addressed by
> > another patch
> > - Move clock properties into 'Optional properties:' section
>
> As mentioned in the reply to v1: Marking the clocks as optional doesn't
> make sense when the driver actually requires them (Or be prepared when
> somebody sends in a patch 'fixing' the driver according to the binding).
> IMO we should just mention the clocks are optional on PowerPC.
Okay, the whole thing becomes quite uncertain to me. The reason of this
v2 is that I got reminded by Gerhard's comment that we've had a time the
driver works with DT without these properties. At that time, the clock
driver provides the clock lookups for the device by calling
clk_register_clkdev(). But on the other hand, I agree with you that it
does not make sense to binding users, because the IP requires these
clock inputs when it gets integrated on a SoC, and the driver requires
these clocks to work.
Shawn
--
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
* Re: [PATCH v5] bus: imx-weim: support CS GPR configuration
From: Philippe De Muyter @ 2014-02-24 8:25 UTC (permalink / raw)
To: Shawn Guo
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Alexander Shiyan, Huang Shijie, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
Rob Herring, Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20140224020455.GA25457-rvtDTF3kK1ictlrPMvKcciBecyulp+rMXqFh9Ls21Oc@public.gmane.org>
On Mon, Feb 24, 2014 at 10:04:59AM +0800, Shawn Guo wrote:
> On Tue, Feb 18, 2014 at 02:41:06PM +0800, Shawn Guo wrote:
> > For imx50-weim and imx6q-weim type of devices, there might a WEIM CS
> > space configuration register in General Purpose Register controller,
> > e.g. IOMUXC_GPR1 on i.MX6Q.
> >
> > Depending on which configuration of the following 4 is chosen for given
> > system, IOMUXC_GPR1[11:0] should be set up as 05, 033, 0113 or 01111
> > correspondingly.
> >
> > CS0(128M) CS1(0M) CS2(0M) CS3(0M)
> > CS0(64M) CS1(64M) CS2(0M) CS3(0M)
> > CS0(64M) CS1(32M) CS2(32M) CS3(0M)
> > CS0(32M) CS1(32M) CS2(32M) CS3(32M)
> >
> > The patch creates a function for such type of devices, which scans
> > 'ranges' property of WEIM node and build the GPR value incrementally.
> > Thus the WEIM CS GPR can be set up automatically at boot time.
> >
> > Signed-off-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>
> Philippe,
>
> Any further comments? Or can I have your Reviewed-by or Tested-by tag?
Yep, sorry. of course :
Reviewed-by: Philippe De Muyter <phdm-vQo90/bmh3WzQB+pC5nmwQ@public.gmane.org>
Tested-by: Philippe De Muyter <phdm-vQo90/bmh3WzQB+pC5nmwQ@public.gmane.org>
And also a 'thank you, Shawn'
Philippe
--
Philippe De Muyter +32 2 6101532 Macq SA rue de l'Aeronef 2 B-1140 Bruxelles
--
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
* RE: [PATCH RESEND v2 1/3] usb: chipidea: msm: Add device tree binding information
From: Peter Chen @ 2014-02-24 8:15 UTC (permalink / raw)
To: Ivan T. Ivanov, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Rob Landley
Cc: Greg Kroah-Hartman, David Brown, devicetree@vger.kernel.org,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-arm-msm@vger.kernel.org, linux-usb@vger.kernel.org
In-Reply-To: <1392889988-24312-1-git-send-email-iivanov@mm-sol.com>
> +CI13xxx (Chipidea) USB controllers
> +
> +Required properties:
> +- compatible: should contain "qcom,ci-hdrc"
> +- reg: offset and length of the register set in the memory map
> +- interrupts: interrupt-specifier for the controller interrupt.
> +- usb-phy: phandle for the PHY device
> +- dr_mode: Sould be "peripheral"
> +
> + gadget@f9a55000 {
> + compatible = "qcom,ci-hdrc";
> + reg = <0xf9a55000 0x400>;
> + dr_mode = "peripheral";
> + interrupts = <0 134 0>;
> + usb-phy = <&usb_otg>;
> + };
> +
usb_otg is not a good name for the node of usb phy.
Peter
^ permalink raw reply
* Re: [PATCH 07/10] spi: sh-msiof: Add support for R-Car H2 and M2
From: Magnus Damm @ 2014-02-24 8:09 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Mark Brown, Takashi Yoshii, linux-spi, SH-Linux, linux-kernel,
Geert Uytterhoeven, devicetree@vger.kernel.org
In-Reply-To: <CAMuHMdV1iDHz4ewFAG-QTba_wUF76Ei-VQpP+MRoNGV2mfHrpw@mail.gmail.com>
Hi Geert,
On Mon, Feb 24, 2014 at 4:39 PM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> Hi Magnus,
>
> On Mon, Feb 24, 2014 at 3:45 AM, Magnus Damm <magnus.damm@gmail.com> wrote:
>> On Fri, Feb 21, 2014 at 1:13 AM, Geert Uytterhoeven
>> <geert@linux-m68k.org> wrote:
>>> On Thu, Feb 20, 2014 at 4:41 PM, Magnus Damm <magnus.damm@gmail.com> wrote:
>>>> On thing stuck out a bit with the bindings. I can see that you specify
>>>> both fifo size and use the SoC suffix for the r8a7790 and r8a7791
>>>> bindings. Isn't that a bit of redundant information there, if we know
>>>> that the SoC is r8a7790 or r8a7791 then can't we simply put that
>>>> information in r8a779x_data above and perhaps keep the binding
>>>> simpler? Perhaps same thing applies to other properties as well?
>>>
>>> "renesas,tx-fifo-size" and "renesas,rx-fifo-size" are part of the existing
>>> bindings, so I'm a bit reluctant to change these.
>>> Hmm, since the original bindings didn't specify the default values,
>>> I could make them chip-specific, though.
>>
>> Thanks, yes I think treating the "renesas,tx-fifo-size" and
>> "renesas,rx-fifo-size" bindings as optional and allow us to rely on
>> chip-specific default values makes sense.
>>
>>> The only other property is "num-cs", which can have any value if you
>>> start using the generic "cs-gpios".
>>
>> I see. It looks to me that such a setting is board-specific, so what
>> is a sane default in the SoC DTSI? You seem to have it set to "1"
>> today, but if the board is supposed to override it anyway then do we
>> need to set it?
>>
>> Anyway, "num-cs" is a minor detail so no need to bother about that too much!
>
> In v2, I'll drop the "num-cs" from the dtsi, so it will default to the driver's
> default (which is 1, for the simple case of using hardware controlled CS).
Sounds good, thanks for your help!
/ magnus
^ permalink raw reply
* Re: [PATCH v2] dt/bindings: fsl-fec: add clock properties
From: Sascha Hauer @ 2014-02-24 7:53 UTC (permalink / raw)
To: Shawn Guo
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Mark Rutland,
Gerhard Sittig, Philippe De Muyter
In-Reply-To: <1393206490-25234-1-git-send-email-shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
On Mon, Feb 24, 2014 at 09:48:10AM +0800, Shawn Guo wrote:
> Update fsl-fec.txt to add 'clocks' and 'clock-names' properties.
>
> Signed-off-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
> Changes since v1:
> - Leave compatible change out, which should probably be addressed by
> another patch
> - Move clock properties into 'Optional properties:' section
As mentioned in the reply to v1: Marking the clocks as optional doesn't
make sense when the driver actually requires them (Or be prepared when
somebody sends in a patch 'fixing' the driver according to the binding).
IMO we should just mention the clocks are optional on PowerPC.
Sascha
>
> Documentation/devicetree/bindings/net/fsl-fec.txt | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt
> index 845ff84..468736d 100644
> --- a/Documentation/devicetree/bindings/net/fsl-fec.txt
> +++ b/Documentation/devicetree/bindings/net/fsl-fec.txt
> @@ -16,6 +16,15 @@ Optional properties:
> will have the duration be 1 millisecond. Numbers greater than 1000 are
> invalid and 1 millisecond will be used instead.
> - phy-supply: regulator that powers the Ethernet PHY.
> +- clocks: the clocks feeding the FEC controller and phy.
> + - "ipg": the peripheral access clock
> + - "ahb": the bus clock for MAC
> + - "ptp": the sampling clock for PTP (IEEE 1588). On SoC like i.MX6Q,
> + the clock could come from either the internal clock control module
> + or external oscillator via pad depending on board design.
> + - "enet_out": the phy reference clock provided by SoC via pad, which
> + is available on SoC like i.MX28.
> +- clock-names: Must contain the clock names described just above
>
> Example:
>
> --
> 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
>
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
--
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
* Re: [PATCH 1/6] usb: gadget: gr_udc: Make struct platform_device variable name clearer
From: Andreas Larsson @ 2014-02-24 7:40 UTC (permalink / raw)
To: balbi-l0cyMroinI0
Cc: Greg Kroah-Hartman, Mark Rutland,
linux-usb-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
software-FkzTOoA/JUlBDgjK7y7TUQ
In-Reply-To: <20140218155253.GC9878-HgARHv6XitL9zxVx7UNMDg@public.gmane.org>
On 2014-02-18 16:52, Felipe Balbi wrote:
> On Thu, Jan 09, 2014 at 11:54:13AM +0100, Andreas Larsson wrote:
>> Rename struct platform_device pointers from ofdev to pdev for clarity.
>> Suggested by Mark Rutland.
>>
>> Signed-off-by: Andreas Larsson <andreas-FkzTOoA/JUlBDgjK7y7TUQ@public.gmane.org>
>> ---
>> drivers/usb/gadget/gr_udc.c | 18 +++++++++---------
>> 1 file changed, 9 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c
>> index 914cbd8..e66dcf0 100644
>> --- a/drivers/usb/gadget/gr_udc.c
>> +++ b/drivers/usb/gadget/gr_udc.c
>> @@ -2071,9 +2071,9 @@ static int gr_udc_init(struct gr_udc *dev)
>> return 0;
>> }
>>
>> -static int gr_remove(struct platform_device *ofdev)
>> +static int gr_remove(struct platform_device *pdev)
>> {
>> - struct gr_udc *dev = dev_get_drvdata(&ofdev->dev);
>> + struct gr_udc *dev = dev_get_drvdata(&pdev->dev);
>
> you can use platform_get_drvdata()
>
>> @@ -2083,7 +2083,7 @@ static int gr_remove(struct platform_device *ofdev)
>> gr_dfs_delete(dev);
>> if (dev->desc_pool)
>> dma_pool_destroy(dev->desc_pool);
>> - dev_set_drvdata(&ofdev->dev, NULL);
>> + dev_set_drvdata(&pdev->dev, NULL);
>
> and platform_set_drvdata()
>
Yes, but wouldn't that be better handled in a separate patch?
Best regards,
Andreas Larsson
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" 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
* Re: [PATCH] dt/bindings: update fsl-fec regarding compatible and clocks
From: Sascha Hauer @ 2014-02-24 7:39 UTC (permalink / raw)
To: Gerhard Sittig
Cc: Mark Rutland, devicetree, Pawel Moll, Ian Campbell,
Philippe De Muyter, Rob Herring, Kumar Gala, Shawn Guo,
linux-arm-kernel
In-Reply-To: <20140222182806.GF3327@book.gsilab.sittig.org>
On Sat, Feb 22, 2014 at 07:28:06PM +0100, Gerhard Sittig wrote:
> On Tue, Feb 18, 2014 at 22:46 +0800, Shawn Guo wrote:
> >
> > On Tue, Feb 18, 2014 at 02:44:30PM +0100, Gerhard Sittig wrote:
> > > [ ... ]
> >
> > > > > > - reg : Address and length of the register set for the device
> > > > > > - interrupts : Should contain fec interrupt
> > > > > > +- clocks: phandle to the clocks feeding the FEC controller and phy. The
> > > > > > + following two are required:
> > > > > > + - "ipg": the peripheral access clock
> > > > > > + - "ahb": the bus clock for MAC
> > > > > > + The following two are optional:
> > > > > > + - "ptp": the sampling clock for PTP (IEEE 1588). On SoC like i.MX6Q,
> > > > > > + the clock could come from either the internal clock control module
> > > > > > + or external oscillator via pad depending on board design.
> > > > > > + - "enet_out": the phy reference clock provided by SoC via pad, which
> > > > > > + is available on SoC like i.MX28.
> > > > > > +- clock-names: Must contain the clock names described just above
> > > > > > +
> > > > >
> > > > > Listing 'clocks' under the "required properties" all of a sudden
> > > > > invalidates existing device trees, if they don't carry the
> > > > > property which before the change was not required, not even
> > > > > documented.
> > > >
> > > > Since the day we move to device tree clock lookup, the driver fec_main
> > > > does not probe at all if the property is absent.
> > >
> > > That's an implementation detail. It's not what the spec says,
> > > and neither is what the spec is to blindly follow after the / a
> > > driver created the fact. Instead, a binding gets designed, and
> > > the software follows.
> > >
> > > In reality, the doc may be behind as developers are more
> > > concerned about the code. But still when you "update" the
> > > binding, don't break compatibility! Even if you'd adjust all
> > > drivers you can spot, it's still only Linux and not all device
> > > tree users.
> >
> > So what's your suggestion? Add the properties as the optional?
>
> Have there been i.MX device trees in mainline releases which lack
> the clock specs? If so, making the clock specs mandatory breaks
> backwards compatibility for these existing device trees as well.
>
> I assume that listing the clocks as optional keeps the binding
> most compatible. You might as well list them as recommended, if
> optional is "too weak" for you.
Why should we keep the binding compatible when the driver requires the
clocks? The clocks are not at all optional for the driver. We made the
clocks mandatory at a time when the bindings didn't make any promises
about stability, so Shawn only documents what the driver requires
anyway.
If anything, we should doument that this binding is not valid for the
PowerPC variants of the FEC.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [PATCH 07/10] spi: sh-msiof: Add support for R-Car H2 and M2
From: Geert Uytterhoeven @ 2014-02-24 7:39 UTC (permalink / raw)
To: Magnus Damm
Cc: Mark Brown, Takashi Yoshii, linux-spi, SH-Linux, linux-kernel,
Geert Uytterhoeven, devicetree@vger.kernel.org
In-Reply-To: <CANqRtoSJTROkkbGxV_p+B2S7b7jZ7jgHQ+q4_WG54m+Pxgfcpw@mail.gmail.com>
Hi Magnus,
On Mon, Feb 24, 2014 at 3:45 AM, Magnus Damm <magnus.damm@gmail.com> wrote:
> On Fri, Feb 21, 2014 at 1:13 AM, Geert Uytterhoeven
> <geert@linux-m68k.org> wrote:
>> On Thu, Feb 20, 2014 at 4:41 PM, Magnus Damm <magnus.damm@gmail.com> wrote:
>>> On thing stuck out a bit with the bindings. I can see that you specify
>>> both fifo size and use the SoC suffix for the r8a7790 and r8a7791
>>> bindings. Isn't that a bit of redundant information there, if we know
>>> that the SoC is r8a7790 or r8a7791 then can't we simply put that
>>> information in r8a779x_data above and perhaps keep the binding
>>> simpler? Perhaps same thing applies to other properties as well?
>>
>> "renesas,tx-fifo-size" and "renesas,rx-fifo-size" are part of the existing
>> bindings, so I'm a bit reluctant to change these.
>> Hmm, since the original bindings didn't specify the default values,
>> I could make them chip-specific, though.
>
> Thanks, yes I think treating the "renesas,tx-fifo-size" and
> "renesas,rx-fifo-size" bindings as optional and allow us to rely on
> chip-specific default values makes sense.
>
>> The only other property is "num-cs", which can have any value if you
>> start using the generic "cs-gpios".
>
> I see. It looks to me that such a setting is board-specific, so what
> is a sane default in the SoC DTSI? You seem to have it set to "1"
> today, but if the board is supposed to override it anyway then do we
> need to set it?
>
> Anyway, "num-cs" is a minor detail so no need to bother about that too much!
In v2, I'll drop the "num-cs" from the dtsi, so it will default to the driver's
default (which is 1, for the simple case of using hardware controlled CS).
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH] sdhci: Add a quirk to disable write-protect
From: Mike Looijmans @ 2014-02-24 6:59 UTC (permalink / raw)
To: linux-mmc, anton; +Cc: linux-kernel, devicetree, cjb, Mike Looijmans
When a board does not have the WP line wired at all, the card
may be detected as read-only. Add a quirk and a device property
to disable WP detection.
Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
---
drivers/mmc/host/sdhci-pltfm.c | 3 +++
drivers/mmc/host/sdhci.c | 3 ++-
include/linux/mmc/sdhci.h | 2 ++
3 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index e2065a4..9e83ada 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -83,6 +83,9 @@ void sdhci_get_of_property(struct platform_device *pdev)
if (sdhci_of_wp_inverted(np))
host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
+ if (of_get_property(np, "disable-wp", NULL))
+ host->quirks2 |= SDHCI_QUIRK2_DISABLE_WP;
+
if (of_get_property(np, "broken-cd", NULL))
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 7a7fb4f..68f47fc 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1635,7 +1635,8 @@ static int sdhci_check_ro(struct sdhci_host *host)
spin_lock_irqsave(&host->lock, flags);
- if (host->flags & SDHCI_DEVICE_DEAD)
+ if ((host->flags & SDHCI_DEVICE_DEAD) ||
+ (host->quirks2 & SDHCI_QUIRK2_DISABLE_WP))
is_readonly = 0;
else if (host->ops->get_ro)
is_readonly = host->ops->get_ro(host);
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 3e781b8..967dba0 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -98,6 +98,8 @@ struct sdhci_host {
#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON (1<<4)
/* Controller has a non-standard host control register */
#define SDHCI_QUIRK2_BROKEN_HOST_CONTROL (1<<5)
+/* Controller lacks write protect detection */
+#define SDHCI_QUIRK2_DISABLE_WP (1<<6)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
--
1.7.9.5
^ permalink raw reply related
* [PATCH] ASoC: cs42888: Add codec driver support
From: Nicolin Chen @ 2014-02-24 6:55 UTC (permalink / raw)
To: broonie, brian.austin, Paul.Handrigan
Cc: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, rob,
lgirdwood, grant.likely, devicetree, linux-doc, linux-kernel,
alsa-devel
This patch adds support for the Cirrus Logic CS42888 Audio CODEC that
has four 24-bit A/D and eight 24-bit D/A converters.
[ CS42888 supports both I2C and SPI control ports. As initial patch,
this patch only adds the support for I2C. ]
Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
---
.../devicetree/bindings/sound/cs42888.txt | 27 +
sound/soc/codecs/Kconfig | 5 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/cs42888.c | 552 +++++++++++++++++++++
sound/soc/codecs/cs42888.h | 209 ++++++++
5 files changed, 795 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/cs42888.txt
create mode 100644 sound/soc/codecs/cs42888.c
create mode 100644 sound/soc/codecs/cs42888.h
diff --git a/Documentation/devicetree/bindings/sound/cs42888.txt b/Documentation/devicetree/bindings/sound/cs42888.txt
new file mode 100644
index 0000000..7736527
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cs42888.txt
@@ -0,0 +1,27 @@
+CS42888 audio CODEC
+
+Required properties:
+
+ - compatible : "cirrus,cs42888"
+
+ - reg : the I2C address of the device for I2C
+
+ - clocks : phandle to the clock source for MCLK
+
+ - clock-names : must contain "mclk".
+
+ - VA-supply, VD-supply, VLS-supply, VLC-supply: power supplies for the device,
+ as covered in Documentation/devicetree/bindings/regulator/regulator.txt
+
+Example:
+
+codec: cs42888@48 {
+ compatible = "cirrus,cs42888";
+ reg = <0x48>;
+ clocks = <&codec_mclk 0>;
+ clock-names = "mclk";
+ VA-supply = <®_audio>;
+ VD-supply = <®_audio>;
+ VLS-supply = <®_audio>;
+ VLC-supply = <®_audio>;
+};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index f2383eb..3211488 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -44,6 +44,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS42L73 if I2C
select SND_SOC_CS4270 if I2C
select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
+ select SND_SOC_CS42888 if I2C
select SND_SOC_CX20442 if TTY
select SND_SOC_DA7210 if I2C
select SND_SOC_DA7213 if I2C
@@ -300,6 +301,10 @@ config SND_SOC_CS4271
tristate "Cirrus Logic CS4271 CODEC"
depends on SND_SOC_I2C_AND_SPI
+config SND_SOC_CS42888
+ tristate "Cirrus Logic CS42888 CODEC"
+ depends on I2C
+
config SND_SOC_CX20442
tristate
depends on TTY
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 6af7a55..75fe757 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -30,6 +30,7 @@ snd-soc-cs42l52-objs := cs42l52.o
snd-soc-cs42l73-objs := cs42l73.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cs4271-objs := cs4271.o
+snd-soc-cs42888-objs := cs42888.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
snd-soc-da7213-objs := da7213.o
@@ -173,6 +174,7 @@ obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
+obj-$(CONFIG_SND_SOC_CS42888) += snd-soc-cs42888.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o
diff --git a/sound/soc/codecs/cs42888.c b/sound/soc/codecs/cs42888.c
new file mode 100644
index 0000000..8561a25
--- /dev/null
+++ b/sound/soc/codecs/cs42888.c
@@ -0,0 +1,552 @@
+/*
+ * Cirrus Logic CS42888 Audio CODEC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include "cs42888.h"
+
+#define CS42888_NUM_SUPPLIES 4
+static const char *cs42888_supply_names[CS42888_NUM_SUPPLIES] = {
+ "VA",
+ "VD",
+ "VLS",
+ "VLC",
+};
+
+#define CS42888_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+/* codec private data */
+struct cs42888_priv {
+ struct regulator_bulk_data supplies[CS42888_NUM_SUPPLIES];
+ struct regmap *regmap;
+ struct clk *clk;
+
+ bool slave_mode;
+ unsigned long sysclk;
+};
+
+/* -127.5dB to 0dB with step of 0.5dB */
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+/* -64dB to 24dB with step of 0.5dB */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -6400, 50, 0);
+
+static const char *cs42888_adc_single[] = { "Differential", "Single-Ended" };
+static const char *cs42888_szc[] = { "Immediate Change", "Zero Cross",
+ "Soft Ramp", "Soft Ramp on Zero Cross" };
+
+static const struct soc_enum cs42888_enum[] = {
+ SOC_ENUM_SINGLE(CS42888_ADCCTL, 4, 2, cs42888_adc_single),
+ SOC_ENUM_SINGLE(CS42888_ADCCTL, 3, 2, cs42888_adc_single),
+ SOC_ENUM_SINGLE(CS42888_TXCTL, 5, 4, cs42888_szc),
+ SOC_ENUM_SINGLE(CS42888_TXCTL, 0, 4, cs42888_szc),
+};
+
+static const struct snd_kcontrol_new cs42888_snd_controls[] = {
+ SOC_DOUBLE_R_TLV("DAC1 Playback Volume", CS42888_VOLAOUT1,
+ CS42888_VOLAOUT2, 0, 0xff, 1, dac_tlv),
+ SOC_DOUBLE_R_TLV("DAC2 Playback Volume", CS42888_VOLAOUT3,
+ CS42888_VOLAOUT4, 0, 0xff, 1, dac_tlv),
+ SOC_DOUBLE_R_TLV("DAC3 Playback Volume", CS42888_VOLAOUT5,
+ CS42888_VOLAOUT6, 0, 0xff, 1, dac_tlv),
+ SOC_DOUBLE_R_TLV("DAC4 Playback Volume", CS42888_VOLAOUT7,
+ CS42888_VOLAOUT8, 0, 0xff, 1, dac_tlv),
+ SOC_DOUBLE_R_S_TLV("ADC1 Capture Volume", CS42888_VOLAIN1,
+ CS42888_VOLAIN2, 0, -0x80, 0x30, 7, 0, adc_tlv),
+ SOC_DOUBLE_R_S_TLV("ADC2 Capture Volume", CS42888_VOLAIN3,
+ CS42888_VOLAIN4, 0, -0x80, 0x30, 7, 0, adc_tlv),
+ SOC_DOUBLE("DAC1 Invert Switch", CS42888_DACINV, 0, 1, 1, 0),
+ SOC_DOUBLE("DAC2 Invert Switch", CS42888_DACINV, 2, 3, 1, 0),
+ SOC_DOUBLE("DAC3 Invert Switch", CS42888_DACINV, 4, 5, 1, 0),
+ SOC_DOUBLE("DAC4 Invert Switch", CS42888_DACINV, 6, 7, 1, 0),
+ SOC_DOUBLE("ADC1 Invert Switch", CS42888_ADCINV, 0, 1, 1, 0),
+ SOC_DOUBLE("ADC2 Invert Switch", CS42888_ADCINV, 2, 3, 1, 0),
+ SOC_SINGLE("ADC High-Pass Filter Switch", CS42888_ADCCTL, 7, 1, 1),
+ SOC_SINGLE("DAC De-emphasis Switch", CS42888_ADCCTL, 5, 1, 0),
+ SOC_ENUM("ADC1 Single Ended Mode Switch", cs42888_enum[0]),
+ SOC_ENUM("ADC2 Single Ended Mode Switch", cs42888_enum[1]),
+ SOC_SINGLE("DAC Single Volume Control Switch", CS42888_TXCTL, 7, 1, 0),
+ SOC_ENUM("DAC Soft Ramp & Zero Cross Control Switch", cs42888_enum[2]),
+ SOC_SINGLE("DAC Auto Mute Switch", CS42888_TXCTL, 4, 1, 0),
+ SOC_SINGLE("Mute ADC Serial Port Switch", CS42888_TXCTL, 3, 1, 0),
+ SOC_SINGLE("ADC Single Volume Control Switch", CS42888_TXCTL, 2, 1, 0),
+ SOC_ENUM("ADC Soft Ramp & Zero Cross Control Switch", cs42888_enum[3]),
+};
+
+static const struct snd_soc_dapm_widget cs42888_dapm_widgets[] = {
+ SND_SOC_DAPM_DAC("DAC1", "Playback", CS42888_PWRCTL, 1, 1),
+ SND_SOC_DAPM_DAC("DAC2", "Playback", CS42888_PWRCTL, 2, 1),
+ SND_SOC_DAPM_DAC("DAC3", "Playback", CS42888_PWRCTL, 3, 1),
+ SND_SOC_DAPM_DAC("DAC4", "Playback", CS42888_PWRCTL, 4, 1),
+
+ SND_SOC_DAPM_OUTPUT("AOUT1L"),
+ SND_SOC_DAPM_OUTPUT("AOUT1R"),
+ SND_SOC_DAPM_OUTPUT("AOUT2L"),
+ SND_SOC_DAPM_OUTPUT("AOUT2R"),
+ SND_SOC_DAPM_OUTPUT("AOUT3L"),
+ SND_SOC_DAPM_OUTPUT("AOUT3R"),
+ SND_SOC_DAPM_OUTPUT("AOUT4L"),
+ SND_SOC_DAPM_OUTPUT("AOUT4R"),
+
+ SND_SOC_DAPM_ADC("ADC1", "Capture", CS42888_PWRCTL, 5, 1),
+ SND_SOC_DAPM_ADC("ADC2", "Capture", CS42888_PWRCTL, 6, 1),
+
+ SND_SOC_DAPM_INPUT("AIN1L"),
+ SND_SOC_DAPM_INPUT("AIN1R"),
+ SND_SOC_DAPM_INPUT("AIN2L"),
+ SND_SOC_DAPM_INPUT("AIN2R"),
+
+ SND_SOC_DAPM_SUPPLY("PWR", CS42888_PWRCTL, 0, 1, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route cs42888_dapm_routes[] = {
+ /* Playback */
+ { "AOUT1L", NULL, "DAC1" },
+ { "AOUT1R", NULL, "DAC1" },
+ { "DAC1", NULL, "PWR" },
+
+ { "AOUT2L", NULL, "DAC2" },
+ { "AOUT2R", NULL, "DAC2" },
+ { "DAC2", NULL, "PWR" },
+
+ { "AOUT3L", NULL, "DAC3" },
+ { "AOUT3R", NULL, "DAC3" },
+ { "DAC3", NULL, "PWR" },
+
+ { "AOUT4L", NULL, "DAC4" },
+ { "AOUT4R", NULL, "DAC4" },
+ { "DAC4", NULL, "PWR" },
+
+ /* Capture */
+ { "ADC1", NULL, "AIN1L" },
+ { "ADC1", NULL, "AIN1R" },
+ { "ADC1", NULL, "PWR" },
+
+ { "ADC2", NULL, "AIN2L" },
+ { "ADC2", NULL, "AIN2R" },
+ { "ADC2", NULL, "PWR" },
+};
+
+struct cs42888_ratios {
+ unsigned int ratio;
+ unsigned char speed;
+ unsigned char mclk;
+};
+
+static struct cs42888_ratios cs42888_ratios[] = {
+ { 64, CS42888_FM_QUAD, CS42888_FUNCMOD_MFREQ_256(4) },
+ { 96, CS42888_FM_QUAD, CS42888_FUNCMOD_MFREQ_384(4) },
+ { 128, CS42888_FM_QUAD, CS42888_FUNCMOD_MFREQ_512(4) },
+ { 192, CS42888_FM_QUAD, CS42888_FUNCMOD_MFREQ_768(4) },
+ { 256, CS42888_FM_SINGLE, CS42888_FUNCMOD_MFREQ_256(1) },
+ { 384, CS42888_FM_SINGLE, CS42888_FUNCMOD_MFREQ_384(1) },
+ { 512, CS42888_FM_SINGLE, CS42888_FUNCMOD_MFREQ_512(1) },
+ { 768, CS42888_FM_SINGLE, CS42888_FUNCMOD_MFREQ_768(1) },
+ { 1024, CS42888_FM_SINGLE, CS42888_FUNCMOD_MFREQ_1024(1) }
+};
+
+static int cs42888_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs42888_priv *cs42888 = snd_soc_codec_get_drvdata(codec);
+
+ cs42888->sysclk = freq;
+
+ return 0;
+}
+
+static int cs42888_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int format)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs42888_priv *cs42888 = snd_soc_codec_get_drvdata(codec);
+ u32 val;
+
+ /* Set DAI format */
+ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_LEFT_J:
+ val = CS42888_INTF_DAC_DIF_LEFTJ | CS42888_INTF_ADC_DIF_LEFTJ;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ val = CS42888_INTF_DAC_DIF_I2S | CS42888_INTF_ADC_DIF_I2S;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ val = CS42888_INTF_DAC_DIF_RIGHTJ | CS42888_INTF_ADC_DIF_RIGHTJ;
+ break;
+ default:
+ dev_err(codec->dev, "unsupported dai format\n");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(cs42888->regmap, CS42888_INTF,
+ CS42888_INTF_DAC_DIF_MASK |
+ CS42888_INTF_ADC_DIF_MASK, val);
+
+ /* Set master/slave audio interface */
+ switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ cs42888->slave_mode = true;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ cs42888->slave_mode = false;
+ break;
+ default:
+ dev_err(codec->dev, "unsupported master/slave mode\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cs42888_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct cs42888_priv *cs42888 = snd_soc_codec_get_drvdata(codec);
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ u32 ratio = cs42888->sysclk / params_rate(params);
+ u32 i, fm, val, mask;
+
+ for (i = 0; i < ARRAY_SIZE(cs42888_ratios); i++) {
+ if (cs42888_ratios[i].ratio == ratio)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(cs42888_ratios)) {
+ dev_err(codec->dev, "unsupported sysclk ratio\n");
+ return -EINVAL;
+ }
+
+ mask = CS42888_FUNCMOD_MFREQ_MASK;
+ val = cs42888_ratios[i].mclk;
+
+ fm = cs42888->slave_mode ? CS42888_FM_AUTO : cs42888_ratios[i].speed;
+
+ regmap_update_bits(cs42888->regmap, CS42888_FUNCMOD,
+ CS42888_FUNCMOD_xC_FM_MASK(tx) | mask,
+ CS42888_FUNCMOD_xC_FM(tx, fm) | val);
+
+ return 0;
+}
+
+static int cs42888_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cs42888_priv *cs42888 = snd_soc_codec_get_drvdata(codec);
+
+ regmap_update_bits(cs42888->regmap, CS42888_DACMUTE,
+ CS42888_DACMUTE_ALL, mute ? CS42888_DACMUTE_ALL : 0);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops cs42888_dai_ops = {
+ .set_fmt = cs42888_set_dai_fmt,
+ .set_sysclk = cs42888_set_dai_sysclk,
+ .hw_params = cs42888_hw_params,
+ .digital_mute = cs42888_digital_mute,
+};
+
+static struct snd_soc_dai_driver cs42888_dai = {
+ .name = "cs42888",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = CS42888_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = CS42888_FORMATS,
+ },
+ .ops = &cs42888_dai_ops,
+};
+
+static struct reg_default cs42888_reg[] = {
+ { 0x01, 0x01 }, /* Chip I.D. and Revision Register */
+ { 0x02, 0x00 }, /* Power Control */
+ { 0x03, 0xF0 }, /* Functional Mode */
+ { 0x04, 0x46 }, /* Interface Formats */
+ { 0x05, 0x00 }, /* ADC Control & DAC De-Emphasis */
+ { 0x06, 0x10 }, /* Transition Control */
+ { 0x07, 0x00 }, /* DAC Channel Mute */
+ { 0x08, 0x00 }, /* Volume Control AOUT1 */
+ { 0x09, 0x00 }, /* Volume Control AOUT2 */
+ { 0x0a, 0x00 }, /* Volume Control AOUT3 */
+ { 0x0b, 0x00 }, /* Volume Control AOUT4 */
+ { 0x0c, 0x00 }, /* Volume Control AOUT5 */
+ { 0x0d, 0x00 }, /* Volume Control AOUT6 */
+ { 0x0e, 0x00 }, /* Volume Control AOUT7 */
+ { 0x0f, 0x00 }, /* Volume Control AOUT8 */
+ { 0x10, 0x00 }, /* DAC Channel Invert */
+ { 0x11, 0x00 }, /* Volume Control AIN1 */
+ { 0x12, 0x00 }, /* Volume Control AIN2 */
+ { 0x13, 0x00 }, /* Volume Control AIN3 */
+ { 0x14, 0x00 }, /* Volume Control AIN4 */
+ { 0x17, 0x00 }, /* ADC Channel Invert */
+ { 0x18, 0x00 }, /* Status Control */
+ { 0x1a, 0x00 }, /* Status Mask */
+ { 0x1b, 0x00 }, /* MUTEC Pin Control */
+};
+
+static bool cs42888_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42888_STATUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs42888_writeable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42888_CHIPID:
+ case CS42888_STATUS:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static const struct regmap_config cs42888_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = CS42888_LASTREG,
+ .reg_defaults = cs42888_reg,
+ .num_reg_defaults = ARRAY_SIZE(cs42888_reg),
+ .volatile_reg = cs42888_volatile_register,
+ .writeable_reg = cs42888_writeable_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int cs42888_probe(struct snd_soc_codec *codec)
+{
+ struct cs42888_priv *cs42888 = snd_soc_codec_get_drvdata(codec);
+
+ /* Disable auto-mute */
+ regmap_update_bits(cs42888->regmap, CS42888_TXCTL,
+ CS42888_TXCTL_AMUTE | CS42888_TXCTL_DAC_SZC_MASK,
+ CS42888_TXCTL_DAC_SZC_SR);
+
+ /* Mute all DAC channels */
+ regmap_write(cs42888->regmap, CS42888_DACMUTE, CS42888_DACMUTE_ALL);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver cs42888_driver = {
+ .probe = cs42888_probe,
+ .idle_bias_off = true,
+
+ .controls = cs42888_snd_controls,
+ .num_controls = ARRAY_SIZE(cs42888_snd_controls),
+ .dapm_widgets = cs42888_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs42888_dapm_widgets),
+ .dapm_routes = cs42888_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(cs42888_dapm_routes),
+};
+
+static int cs42888_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct cs42888_priv *cs42888;
+ int ret, val, i;
+
+ cs42888 = devm_kzalloc(&i2c->dev, sizeof(*cs42888), GFP_KERNEL);
+ if (cs42888 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, cs42888);
+
+ cs42888->clk = devm_clk_get(&i2c->dev, "mclk");
+ if (IS_ERR(cs42888->clk))
+ dev_warn(&i2c->dev, "failed to get the clock: %ld\n",
+ PTR_ERR(cs42888->clk));
+ else
+ cs42888->sysclk = clk_get_rate(cs42888->clk);
+
+ for (i = 0; i < ARRAY_SIZE(cs42888->supplies); i++)
+ cs42888->supplies[i].supply = cs42888_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&i2c->dev,
+ ARRAY_SIZE(cs42888->supplies), cs42888->supplies);
+ if (ret) {
+ dev_err(&i2c->dev, "failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs42888->supplies),
+ cs42888->supplies);
+ if (ret) {
+ dev_err(&i2c->dev, "failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ /* Make sure hardware reset done */
+ msleep(5);
+
+ cs42888->regmap = devm_regmap_init_i2c(i2c, &cs42888_regmap);
+ if (IS_ERR(cs42888->regmap)) {
+ ret = PTR_ERR(cs42888->regmap);
+ dev_err(&i2c->dev, "failed to allocate regmap: %d\n", ret);
+ goto err_enable;
+ }
+
+ /*
+ * We haven't marked the chip revision as volatile due to
+ * sharing a register with the right input volume; explicitly
+ * bypass the cache to read it.
+ */
+ regcache_cache_bypass(cs42888->regmap, true);
+
+ /* Validate the chip ID */
+ regmap_read(cs42888->regmap, CS42888_CHIPID, &val);
+ if (val < 0) {
+ dev_err(&i2c->dev, "failed to get device ID: %x", val);
+ ret = -EINVAL;
+ goto err_enable;
+ }
+
+ /* The top four bits of the chip ID should be 0000 */
+ if ((val & CS42888_CHIPID_CHIP_ID_MASK) != 0x00) {
+ dev_err(&i2c->dev, "unmatched chip ID: %d\n",
+ val & CS42888_CHIPID_CHIP_ID_MASK);
+ ret = -EINVAL;
+ goto err_enable;
+ }
+
+ dev_info(&i2c->dev, "found device at %X, revision %X\n",
+ i2c->addr, val & CS42888_CHIPID_REV_ID_MASK);
+
+ regcache_cache_bypass(cs42888->regmap, false);
+
+ pm_runtime_enable(&i2c->dev);
+ pm_request_idle(&i2c->dev);
+
+ ret = snd_soc_register_codec(&i2c->dev, &cs42888_driver, &cs42888_dai, 1);
+ if (ret) {
+ dev_err(&i2c->dev, "failed to register codec:%d\n", ret);
+ goto err_enable;
+ }
+
+ regcache_cache_only(cs42888->regmap, true);
+
+err_enable:
+ regulator_bulk_disable(ARRAY_SIZE(cs42888->supplies), cs42888->supplies);
+
+ return ret;
+}
+
+static int cs42888_i2c_remove(struct i2c_client *i2c_client)
+{
+ snd_soc_unregister_codec(&i2c_client->dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int cs42888_runtime_resume(struct device *dev)
+{
+ struct cs42888_priv *cs42888 = dev_get_drvdata(dev);
+ int ret;
+
+ if (!IS_ERR(cs42888->clk))
+ clk_prepare_enable(cs42888->clk);
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs42888->supplies),
+ cs42888->supplies);
+ if (ret) {
+ dev_err(dev, "failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * In case the device was put to hard reset during sleep,
+ * we need to wait 500ns here before any I2C communication
+ */
+ mdelay(5);
+
+ regcache_cache_only(cs42888->regmap, false);
+
+ regcache_sync(cs42888->regmap);
+
+ return 0;
+}
+
+static int cs42888_runtime_suspend(struct device *dev)
+{
+ struct cs42888_priv *cs42888 = dev_get_drvdata(dev);
+
+ regcache_cache_only(cs42888->regmap, true);
+
+ regulator_bulk_disable(ARRAY_SIZE(cs42888->supplies),
+ cs42888->supplies);
+
+ if (!IS_ERR(cs42888->clk))
+ clk_disable_unprepare(cs42888->clk);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops cs42888_pm = {
+ SET_RUNTIME_PM_OPS(cs42888_runtime_suspend, cs42888_runtime_resume, NULL)
+};
+
+static struct i2c_device_id cs42888_i2c_id[] = {
+ {"cs42888", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs42888_i2c_id);
+
+static const struct of_device_id cs42888_of_match[] = {
+ { .compatible = "cirrus,cs42888", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cs42888_of_match);
+
+static struct i2c_driver cs42888_i2c_driver = {
+ .driver = {
+ .name = "cs42888",
+ .owner = THIS_MODULE,
+ .of_match_table = cs42888_of_match,
+ .pm = &cs42888_pm,
+ },
+ .probe = cs42888_i2c_probe,
+ .remove = cs42888_i2c_remove,
+ .id_table = cs42888_i2c_id,
+};
+
+module_i2c_driver(cs42888_i2c_driver);
+
+MODULE_DESCRIPTION("Cirrus Logic CS42888 ALSA SoC Codec Driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42888.h b/sound/soc/codecs/cs42888.h
new file mode 100644
index 0000000..6d2cdec
--- /dev/null
+++ b/sound/soc/codecs/cs42888.h
@@ -0,0 +1,209 @@
+/*
+ * cs42888.h - Cirrus Logic CS42888 Audio CODEC driver header file
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _CS42888_H
+#define _CS42888_H
+
+/* CS42888 register map */
+#define CS42888_CHIPID 0x01 /* Chip ID */
+#define CS42888_PWRCTL 0x02 /* Power Control */
+#define CS42888_FUNCMOD 0x03 /* Functional Mode */
+#define CS42888_INTF 0x04 /* Interface Formats */
+#define CS42888_ADCCTL 0x05 /* ADC Control */
+#define CS42888_TXCTL 0x06 /* Transition Control */
+#define CS42888_DACMUTE 0x07 /* DAC Mute Control */
+#define CS42888_VOLAOUT1 0x08 /* Volume Control AOUT1 */
+#define CS42888_VOLAOUT2 0x09 /* Volume Control AOUT2 */
+#define CS42888_VOLAOUT3 0x0A /* Volume Control AOUT3 */
+#define CS42888_VOLAOUT4 0x0B /* Volume Control AOUT4 */
+#define CS42888_VOLAOUT5 0x0C /* Volume Control AOUT5 */
+#define CS42888_VOLAOUT6 0x0D /* Volume Control AOUT6 */
+#define CS42888_VOLAOUT7 0x0E /* Volume Control AOUT7 */
+#define CS42888_VOLAOUT8 0x0F /* Volume Control AOUT8 */
+#define CS42888_DACINV 0x10 /* DAC Channel Invert */
+#define CS42888_VOLAIN1 0x11 /* Volume Control AIN1 */
+#define CS42888_VOLAIN2 0x12 /* Volume Control AIN2 */
+#define CS42888_VOLAIN3 0x13 /* Volume Control AIN3 */
+#define CS42888_VOLAIN4 0x14 /* Volume Control AIN4 */
+#define CS42888_ADCINV 0x17 /* ADC Channel Invert */
+#define CS42888_STATUSCTL 0x18 /* Status Control */
+#define CS42888_STATUS 0x19 /* Status */
+#define CS42888_STATUSM 0x1A /* Status Mask */
+#define CS42888_MUTEC 0x1B /* MUTEC Pin Control */
+
+#define CS42888_FIRSTREG CS42888_CHIPID
+#define CS42888_LASTREG CS42888_MUTEC
+#define CS42888_NUMREGS (CS42888_LASTREG - CS42888_FIRSTREG + 1)
+#define CS42888_I2C_INCR 0x80
+
+/* Chip I.D. and Revision Register (Address 01h) */
+#define CS42888_CHIPID_CHIP_ID_MASK 0xF0
+#define CS42888_CHIPID_REV_ID_MASK 0x0F
+
+/* Power Control (Address 02h) */
+#define CS42888_PWRCTL_PDN_ADC2_SHIFT 6
+#define CS42888_PWRCTL_PDN_ADC2_MASK (1 << CS42888_PWRCTL_PDN_ADC2_SHIFT)
+#define CS42888_PWRCTL_PDN_ADC2 (1 << CS42888_PWRCTL_PDN_ADC2_SHIFT)
+#define CS42888_PWRCTL_PDN_ADC1_SHIFT 5
+#define CS42888_PWRCTL_PDN_ADC1_MASK (1 << CS42888_PWRCTL_PDN_ADC1_SHIFT)
+#define CS42888_PWRCTL_PDN_ADC1 (1 << CS42888_PWRCTL_PDN_ADC1_SHIFT)
+#define CS42888_PWRCTL_PDN_DAC4_SHIFT 4
+#define CS42888_PWRCTL_PDN_DAC4_MASK (1 << CS42888_PWRCTL_PDN_DAC4_SHIFT)
+#define CS42888_PWRCTL_PDN_DAC4 (1 << CS42888_PWRCTL_PDN_DAC4_SHIFT)
+#define CS42888_PWRCTL_PDN_DAC3_SHIFT 3
+#define CS42888_PWRCTL_PDN_DAC3_MASK (1 << CS42888_PWRCTL_PDN_DAC3_SHIFT)
+#define CS42888_PWRCTL_PDN_DAC3 (1 << CS42888_PWRCTL_PDN_DAC3_SHIFT)
+#define CS42888_PWRCTL_PDN_DAC2_SHIFT 2
+#define CS42888_PWRCTL_PDN_DAC2_MASK (1 << CS42888_PWRCTL_PDN_DAC2_SHIFT)
+#define CS42888_PWRCTL_PDN_DAC2 (1 << CS42888_PWRCTL_PDN_DAC2_SHIFT)
+#define CS42888_PWRCTL_PDN_DAC1_SHIFT 1
+#define CS42888_PWRCTL_PDN_DAC1_MASK (1 << CS42888_PWRCTL_PDN_DAC1_SHIFT)
+#define CS42888_PWRCTL_PDN_DAC1 (1 << CS42888_PWRCTL_PDN_DAC1_SHIFT)
+#define CS42888_PWRCTL_PDN_SHIFT 0
+#define CS42888_PWRCTL_PDN_MASK (1 << CS42888_PWRCTL_PDN_SHIFT)
+#define CS42888_PWRCTL_PDN (1 << CS42888_PWRCTL_PDN_SHIFT)
+
+/* Functional Mode (Address 03h) */
+#define CS42888_FUNCMOD_DAC_FM_SHIFT 6
+#define CS42888_FUNCMOD_DAC_FM_WIDTH 2
+#define CS42888_FUNCMOD_DAC_FM_MASK (((1 << CS42888_FUNCMOD_DAC_FM_WIDTH) - 1) << CS42888_FUNCMOD_DAC_FM_SHIFT)
+#define CS42888_FUNCMOD_DAC_FM(v) ((v) << CS42888_FUNCMOD_DAC_FM_SHIFT)
+#define CS42888_FUNCMOD_ADC_FM_SHIFT 4
+#define CS42888_FUNCMOD_ADC_FM_WIDTH 2
+#define CS42888_FUNCMOD_ADC_FM_MASK (((1 << CS42888_FUNCMOD_ADC_FM_WIDTH) - 1) << CS42888_FUNCMOD_ADC_FM_SHIFT)
+#define CS42888_FUNCMOD_ADC_FM(v) ((v) << CS42888_FUNCMOD_ADC_FM_SHIFT)
+#define CS42888_FUNCMOD_xC_FM_MASK(x) ((x) ? CS42888_FUNCMOD_DAC_FM_MASK : CS42888_FUNCMOD_ADC_FM_MASK)
+#define CS42888_FUNCMOD_xC_FM(x, v) ((x) ? CS42888_FUNCMOD_DAC_FM(v) : CS42888_FUNCMOD_ADC_FM(v))
+#define CS42888_FUNCMOD_MFREQ_SHIFT 1
+#define CS42888_FUNCMOD_MFREQ_WIDTH 3
+#define CS42888_FUNCMOD_MFREQ_MASK (((1 << CS42888_FUNCMOD_MFREQ_WIDTH) - 1) << CS42888_FUNCMOD_MFREQ_SHIFT)
+#define CS42888_FUNCMOD_MFREQ_256(s) ((0 << CS42888_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42888_FUNCMOD_MFREQ_384(s) ((1 << CS42888_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42888_FUNCMOD_MFREQ_512(s) ((2 << CS42888_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42888_FUNCMOD_MFREQ_768(s) ((3 << CS42888_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+#define CS42888_FUNCMOD_MFREQ_1024(s) ((4 << CS42888_FUNCMOD_MFREQ_SHIFT) >> (s >> 1))
+
+#define CS42888_FM_SINGLE 0
+#define CS42888_FM_DOUBLE 1
+#define CS42888_FM_QUAD 2
+#define CS42888_FM_AUTO 3
+
+/* Interface Formats (Address 04h) */
+#define CS42888_INTF_FREEZE_SHIFT 7
+#define CS42888_INTF_FREEZE_MASK (1 << CS42888_INTF_FREEZE_SHIFT)
+#define CS42888_INTF_FREEZE (1 << CS42888_INTF_FREEZE_SHIFT)
+#define CS42888_INTF_AUX_DIF_SHIFT 6
+#define CS42888_INTF_AUX_DIF_MASK (1 << CS42888_INTF_AUX_DIF_SHIFT)
+#define CS42888_INTF_AUX_DIF (1 << CS42888_INTF_AUX_DIF_SHIFT)
+#define CS42888_INTF_DAC_DIF_SHIFT 3
+#define CS42888_INTF_DAC_DIF_WIDTH 3
+#define CS42888_INTF_DAC_DIF_MASK (((1 << CS42888_INTF_DAC_DIF_WIDTH) - 1) << CS42888_INTF_DAC_DIF_SHIFT)
+#define CS42888_INTF_DAC_DIF_LEFTJ (0 << CS42888_INTF_DAC_DIF_SHIFT)
+#define CS42888_INTF_DAC_DIF_I2S (1 << CS42888_INTF_DAC_DIF_SHIFT)
+#define CS42888_INTF_DAC_DIF_RIGHTJ (2 << CS42888_INTF_DAC_DIF_SHIFT)
+#define CS42888_INTF_DAC_DIF_RIGHTJ_16 (3 << CS42888_INTF_DAC_DIF_SHIFT)
+#define CS42888_INTF_DAC_DIF_ONELINE_20 (4 << CS42888_INTF_DAC_DIF_SHIFT)
+#define CS42888_INTF_DAC_DIF_ONELINE_24 (6 << CS42888_INTF_DAC_DIF_SHIFT)
+#define CS42888_INTF_DAC_DIF_TDM (7 << CS42888_INTF_DAC_DIF_SHIFT)
+#define CS42888_INTF_ADC_DIF_SHIFT 0
+#define CS42888_INTF_ADC_DIF_WIDTH 3
+#define CS42888_INTF_ADC_DIF_MASK (((1 << CS42888_INTF_ADC_DIF_WIDTH) - 1) << CS42888_INTF_ADC_DIF_SHIFT)
+#define CS42888_INTF_ADC_DIF_LEFTJ (0 << CS42888_INTF_ADC_DIF_SHIFT)
+#define CS42888_INTF_ADC_DIF_I2S (1 << CS42888_INTF_ADC_DIF_SHIFT)
+#define CS42888_INTF_ADC_DIF_RIGHTJ (2 << CS42888_INTF_ADC_DIF_SHIFT)
+#define CS42888_INTF_ADC_DIF_RIGHTJ_16 (3 << CS42888_INTF_ADC_DIF_SHIFT)
+#define CS42888_INTF_ADC_DIF_ONELINE_20 (4 << CS42888_INTF_ADC_DIF_SHIFT)
+#define CS42888_INTF_ADC_DIF_ONELINE_24 (6 << CS42888_INTF_ADC_DIF_SHIFT)
+#define CS42888_INTF_ADC_DIF_TDM (7 << CS42888_INTF_ADC_DIF_SHIFT)
+
+/* ADC Control & DAC De-Emphasis (Address 05h) */
+#define CS42888_ADCCTL_ADC_HPF_FREEZE_SHIFT 7
+#define CS42888_ADCCTL_ADC_HPF_FREEZE_MASK (1 << CS42888_ADCCTL_ADC_HPF_FREEZE_SHIFT)
+#define CS42888_ADCCTL_ADC_HPF_FREEZE (1 << CS42888_ADCCTL_ADC_HPF_FREEZE_SHIFT)
+#define CS42888_ADCCTL_DAC_DEM_SHIFT 5
+#define CS42888_ADCCTL_DAC_DEM_MASK (1 << CS42888_ADCCTL_DAC_DEM_SHIFT)
+#define CS42888_ADCCTL_DAC_DEM (1 << CS42888_ADCCTL_DAC_DEM_SHIFT)
+#define CS42888_ADCCTL_ADC1_SINGLE_SHIFT 4
+#define CS42888_ADCCTL_ADC1_SINGLE_MASK (1 << CS42888_ADCCTL_ADC1_SINGLE_SHIFT)
+#define CS42888_ADCCTL_ADC1_SINGLE (1 << CS42888_ADCCTL_ADC1_SINGLE_SHIFT)
+#define CS42888_ADCCTL_ADC2_SINGLE_SHIFT 3
+#define CS42888_ADCCTL_ADC2_SINGLE_MASK (1 << CS42888_ADCCTL_ADC2_SINGLE_SHIFT)
+#define CS42888_ADCCTL_ADC2_SINGLE (1 << CS42888_ADCCTL_ADC2_SINGLE_SHIFT)
+
+/* Transition Control (Address 06h) */
+#define CS42888_TXCTL_DAC_SNGVOL_SHIFT 7
+#define CS42888_TXCTL_DAC_SNGVOL_MASK (1 << CS42888_TXCTL_DAC_SNGVOL_SHIFT)
+#define CS42888_TXCTL_DAC_SNGVOL (1 << CS42888_TXCTL_DAC_SNGVOL_SHIFT)
+#define CS42888_TXCTL_DAC_SZC_SHIFT 5
+#define CS42888_TXCTL_DAC_SZC_WIDTH 2
+#define CS42888_TXCTL_DAC_SZC_MASK (((1 << CS42888_TXCTL_DAC_SZC_WIDTH) - 1) << CS42888_TXCTL_DAC_SZC_SHIFT)
+#define CS42888_TXCTL_DAC_SZC_IC (0 << CS42888_TXCTL_DAC_SZC_SHIFT)
+#define CS42888_TXCTL_DAC_SZC_ZC (1 << CS42888_TXCTL_DAC_SZC_SHIFT)
+#define CS42888_TXCTL_DAC_SZC_SR (2 << CS42888_TXCTL_DAC_SZC_SHIFT)
+#define CS42888_TXCTL_DAC_SZC_SRZC (3 << CS42888_TXCTL_DAC_SZC_SHIFT)
+#define CS42888_TXCTL_AMUTE_SHIFT 4
+#define CS42888_TXCTL_AMUTE_MASK (1 << CS42888_TXCTL_AMUTE_SHIFT)
+#define CS42888_TXCTL_AMUTE (1 << CS42888_TXCTL_AMUTE_SHIFT)
+#define CS42888_TXCTL_MUTE_ADC_SP_SHIFT 3
+#define CS42888_TXCTL_MUTE_ADC_SP_MASK (1 << CS42888_TXCTL_MUTE_ADC_SP_SHIFT)
+#define CS42888_TXCTL_MUTE_ADC_SP (1 << CS42888_TXCTL_MUTE_ADC_SP_SHIFT)
+#define CS42888_TXCTL_ADC_SNGVOL_SHIFT 2
+#define CS42888_TXCTL_ADC_SNGVOL_MASK (1 << CS42888_TXCTL_ADC_SNGVOL_SHIFT)
+#define CS42888_TXCTL_ADC_SNGVOL (1 << CS42888_TXCTL_ADC_SNGVOL_SHIFT)
+#define CS42888_TXCTL_ADC_SZC_SHIFT 0
+#define CS42888_TXCTL_ADC_SZC_MASK (((1 << CS42888_TXCTL_ADC_SZC_WIDTH) - 1) << CS42888_TXCTL_ADC_SZC_SHIFT)
+#define CS42888_TXCTL_ADC_SZC_IC (0 << CS42888_TXCTL_ADC_SZC_SHIFT)
+#define CS42888_TXCTL_ADC_SZC_ZC (1 << CS42888_TXCTL_ADC_SZC_SHIFT)
+#define CS42888_TXCTL_ADC_SZC_SR (2 << CS42888_TXCTL_ADC_SZC_SHIFT)
+#define CS42888_TXCTL_ADC_SZC_SRZC (3 << CS42888_TXCTL_ADC_SZC_SHIFT)
+
+/* DAC Channel Mute (Address 07h) */
+#define CS42888_DACMUTE_AOUT(n) (0x1 << n)
+#define CS42888_DACMUTE_ALL 0xff
+
+/* Status Control (Address 18h)*/
+#define CS42888_STATUSCTL_INI_SHIFT 2
+#define CS42888_STATUSCTL_INI_WIDTH 2
+#define CS42888_STATUSCTL_INI_MASK (((1 << CS42888_STATUSCTL_INI_WIDTH) - 1) << CS42888_STATUSCTL_INI_SHIFT)
+#define CS42888_STATUSCTL_INT_ACTIVE_HIGH (0 << CS42888_STATUSCTL_INI_SHIFT)
+#define CS42888_STATUSCTL_INT_ACTIVE_LOW (1 << CS42888_STATUSCTL_INI_SHIFT)
+#define CS42888_STATUSCTL_INT_OPEN_DRAIN (2 << CS42888_STATUSCTL_INI_SHIFT)
+
+/* Status (Address 19h)*/
+#define CS42888_STATUS_DAC_CLK_ERR_SHIFT 4
+#define CS42888_STATUS_DAC_CLK_ERR_MASK (1 << CS42888_STATUS_DAC_CLK_ERR_SHIFT)
+#define CS42888_STATUS_ADC_CLK_ERR_SHIFT 3
+#define CS42888_STATUS_ADC_CLK_ERR_MASK (1 << CS42888_STATUS_ADC_CLK_ERR_SHIFT)
+#define CS42888_STATUS_ADC2_OVFL_SHIFT 1
+#define CS42888_STATUS_ADC2_OVFL_MASK (1 << CS42888_STATUS_ADC2_OVFL_SHIFT)
+#define CS42888_STATUS_ADC1_OVFL_SHIFT 0
+#define CS42888_STATUS_ADC1_OVFL_MASK (1 << CS42888_STATUS_ADC1_OVFL_SHIFT)
+
+/* Status Mask (Address 1Ah) */
+#define CS42888_STATUS_DAC_CLK_ERR_M_SHIFT 4
+#define CS42888_STATUS_DAC_CLK_ERR_M_MASK (1 << CS42888_STATUS_DAC_CLK_ERR_M_SHIFT)
+#define CS42888_STATUS_ADC_CLK_ERR_M_SHIFT 3
+#define CS42888_STATUS_ADC_CLK_ERR_M_MASK (1 << CS42888_STATUS_ADC_CLK_ERR_M_SHIFT)
+#define CS42888_STATUS_ADC2_OVFL_M_SHIFT 1
+#define CS42888_STATUS_ADC2_OVFL_M_MASK (1 << CS42888_STATUS_ADC2_OVFL_M_SHIFT)
+#define CS42888_STATUS_ADC1_OVFL_M_SHIFT 0
+#define CS42888_STATUS_ADC1_OVFL_M_MASK (1 << CS42888_STATUS_ADC1_OVFL_M_SHIFT)
+
+/* MUTEC Pin Control (Address 1Bh) */
+#define CS42888_MUTEC_MCPOLARITY_SHIFT 1
+#define CS42888_MUTEC_MCPOLARITY_MASK (1 << CS42888_MUTEC_MCPOLARITY_SHIFT)
+#define CS42888_MUTEC_MCPOLARITY_ACTIVE_LOW (0 << CS42888_MUTEC_MCPOLARITY_SHIFT)
+#define CS42888_MUTEC_MCPOLARITY_ACTIVE_HIGH (1 << CS42888_MUTEC_MCPOLARITY_SHIFT)
+#define CS42888_MUTEC_MUTEC_ACTIVE_SHIFT 0
+#define CS42888_MUTEC_MUTEC_ACTIVE_MASK (1 << CS42888_MUTEC_MUTEC_ACTIVE_SHIFT)
+#define CS42888_MUTEC_MUTEC_ACTIVE (1 << CS42888_MUTEC_MUTEC_ACTIVE_SHIFT)
+#endif /* _CS42888_H */
--
1.8.4
^ permalink raw reply related
* [PATCH v13 3/3] arm64: Add APM X-Gene SoC AHCI SATA host controller DTS entries
From: Loc Ho @ 2014-02-24 5:54 UTC (permalink / raw)
To: olof, tj, arnd
Cc: linux-scsi, linux-ide, devicetree, linux-arm-kernel, ddutile, jcm,
patches, Loc Ho, Tuan Phan, Suman Tripathi
In-Reply-To: <1393221265-13057-3-git-send-email-lho@apm.com>
Signed-off-by: Loc Ho <lho@apm.com>
Signed-off-by: Tuan Phan <tphan@apm.com>
Signed-off-by: Suman Tripathi <stripathi@apm.com>
---
arch/arm64/boot/dts/apm-storm.dtsi | 75 ++++++++++++++++++++++++++++++++++++
1 files changed, 75 insertions(+), 0 deletions(-)
diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi
index c78ddcf..57b0770 100644
--- a/arch/arm64/boot/dts/apm-storm.dtsi
+++ b/arch/arm64/boot/dts/apm-storm.dtsi
@@ -221,6 +221,48 @@
enable-offset = <0x0>;
enable-mask = <0x06>;
};
+
+ sata01clk: sata01clk@1f21c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ clock-names = "socplldiv2";
+ reg = <0x0 0x1f21c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sata01clk";
+ csr-offset = <0x4>;
+ csr-mask = <0x05>;
+ enable-offset = <0x0>;
+ enable-mask = <0x39>;
+ };
+
+ sata23clk: sata23clk@1f22c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ clock-names = "socplldiv2";
+ reg = <0x0 0x1f22c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sata23clk";
+ csr-offset = <0x4>;
+ csr-mask = <0x05>;
+ enable-offset = <0x0>;
+ enable-mask = <0x39>;
+ };
+
+ sata45clk: sata45clk@1f23c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ clock-names = "socplldiv2";
+ reg = <0x0 0x1f23c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sata45clk";
+ csr-offset = <0x4>;
+ csr-mask = <0x05>;
+ enable-offset = <0x0>;
+ enable-mask = <0x39>;
+ };
};
serial0: serial@1c020000 {
@@ -262,5 +304,38 @@
apm,tx-boost-gain = <31 31 31 31 31 31>;
apm,tx-eye-tuning = <2 10 10 2 10 10>;
};
+
+ sata1: sata@1a000000 {
+ compatible = "apm,xgene-ahci-sgmii";
+ reg = <0x0 0x1a000000 0x0 0x1000>,
+ <0x0 0x1f210000 0x0 0x10000>;
+ interrupts = <0x0 0x86 0x4>;
+ status = "disabled";
+ clocks = <&sata01clk 0>;
+ phys = <&phy1 0>;
+ phy-names = "sata-6g";
+ };
+
+ sata2: sata@1a400000 {
+ compatible = "apm,xgene-ahci-sgmii";
+ reg = <0x0 0x1a400000 0x0 0x1000>,
+ <0x0 0x1f220000 0x0 0x10000>;
+ interrupts = <0x0 0x87 0x4>;
+ status = "ok";
+ clocks = <&sata23clk 0>;
+ phys = <&phy2 0>;
+ phy-names = "sata-6g";
+ };
+
+ sata3: sata@1a800000 {
+ compatible = "apm,xgene-ahci-pcie";
+ reg = <0x0 0x1a800000 0x0 0x1000>,
+ <0x0 0x1f230000 0x0 0x10000>;
+ interrupts = <0x0 0x88 0x4>;
+ status = "ok";
+ clocks = <&sata45clk 0>;
+ phys = <&phy3 0>;
+ phy-names = "sata-6g";
+ };
};
};
--
1.5.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