* [PATCH V2 0/7] support the cpts found on am335x devices
From: N, Mugunthan V @ 2012-10-22 10:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121017182714.GC2412@netboy.at.omicron.at>
> -----Original Message-----
> From: Richard Cochran [mailto:richardcochran at gmail.com]
> Sent: Wednesday, October 17, 2012 11:57 PM
> To: N, Mugunthan V
> Cc: netdev at vger.kernel.org; linux-arm-kernel at lists.infradead.org; David
> Miller; Chemparathy, Cyril; Govindarajan, Sriramakrishnan
> Subject: Re: [PATCH V2 0/7] support the cpts found on am335x devices
>
> On Tue, Oct 16, 2012 at 11:11:29PM +0000, N, Mugunthan V wrote:
> >
> > Yes, I do agree that driver handles it. As Half roll over and Full
> roll
> > over events are not handled in the driver, I am just curious how will
> > the misaligned TS would be handled and also in cpts set time, the
> Lower
> > 32 bit time is written to CPTS counter
>
> #include <linux/clocksource.h>
I think the timecounter_init initializes only the software. But still I am
not clear how the time given in cpts_ptp_settime will be projected to
hardware. Can you correct me if I am wrong.
>
> > Since we poll for the 32bit over flow for every HZ * 8 cycle, won't
> > there be a system overhead. If the CPTS ref clock is changed
> according
> > to the ptp freq adjust api, how will the timecounter take care of
> change
> > in frequency
>
> There is nothing to do here. What are you asking?
I think instead of fixing the driver to AM335X, let's make the driver
generic as the same driver can be used to TI814X, TI813X and other
upcoming platforms TI811X where the CPTS ref clock can be changed as
per usage requirement.
>
> > The current driver which is in vanilla kernel doesn't use extended
> slave
> > address which are conflict between TI814x CPSW IP version and AM335x
> CPSW
> > IP version. I have just posted my version of CPTS implementation. May
> be
> > we can work together make the driver compatible with both CPSW
> versions
>
> Okay.
>
> > Since CPSW is a 3port Switch we should not fix time stamping will be
> enabled
> > only for slave 0 or passing slave number through DT. Its better if we
> > can configure both the slaves. This can be tested with EVM-sk which
> has
> > both the slave ports pinned out.
>
> I hope that you meant, "better if we can configure _either_ slave."
> Considering how SO_TIMESTAMPING works, you can't use both at once.
>
Since CPSW as a Ethernet switch, the PTP packet can be delivered to
any downstream port. So if we fix the PTP time stamping to one port
then the driver won't receive time stamping information when the packet
is delivered to the other port.
Regards
Mugunthan V N
^ permalink raw reply
* [PATCH 4/4] ARM/dts: omap5: Update MMC with address space and interrupts
From: Sebastien Guiriec @ 2012-10-22 10:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350901328-3525-1-git-send-email-s-guiriec@ti.com>
Add base address and interrupt line inside Device Tree data for
OMAP5.
Signed-off-by: Sebastien Guiriec <s-guiriec@ti.com>
---
arch/arm/boot/dts/omap5.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index 413df94..b643cd3 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -285,6 +285,8 @@
mmc1: mmc at 4809c000 {
compatible = "ti,omap4-hsmmc";
+ reg = <0x4809c000 0x400>;
+ interrupts = <0 83 0x4>;
ti,hwmods = "mmc1";
ti,dual-volt;
ti,needs-special-reset;
@@ -292,24 +294,32 @@
mmc2: mmc at 480b4000 {
compatible = "ti,omap4-hsmmc";
+ reg = <0x480b4000 0x400>;
+ interrupts = <0 86 0x4>;
ti,hwmods = "mmc2";
ti,needs-special-reset;
};
mmc3: mmc at 480ad000 {
compatible = "ti,omap4-hsmmc";
+ reg = <0x480ad000 0x400>;
+ interrupts = <0 94 0x4>;
ti,hwmods = "mmc3";
ti,needs-special-reset;
};
mmc4: mmc at 480d1000 {
compatible = "ti,omap4-hsmmc";
+ reg = <0x480d1000 0x400>;
+ interrupts = <0 96 0x4>;
ti,hwmods = "mmc4";
ti,needs-special-reset;
};
mmc5: mmc at 480d5000 {
compatible = "ti,omap4-hsmmc";
+ reg = <0x480d5000 0x400>;
+ interrupts = <0 59 0x4>;
ti,hwmods = "mmc5";
ti,needs-special-reset;
};
--
1.7.10.4
^ permalink raw reply related
* [PATCH 3/4] ARM/dts: omap5: Update UART with address space and interrupts
From: Sebastien Guiriec @ 2012-10-22 10:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350901328-3525-1-git-send-email-s-guiriec@ti.com>
Add base address and interrupt line inside Device Tree data for
Signed-off-by: Sebastien Guiriec <s-guiriec@ti.com>
---
arch/arm/boot/dts/omap5.dtsi | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index 6c22e1b..413df94 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -237,36 +237,48 @@
uart1: serial at 4806a000 {
compatible = "ti,omap4-uart";
+ reg = <0x4806a000 0x100>;
+ interrupts = <0 72 0x4>;
ti,hwmods = "uart1";
clock-frequency = <48000000>;
};
uart2: serial at 4806c000 {
compatible = "ti,omap4-uart";
+ reg = <0x4806c000 0x100>;
+ interrupts = <0 73 0x4>;
ti,hwmods = "uart2";
clock-frequency = <48000000>;
};
uart3: serial at 48020000 {
compatible = "ti,omap4-uart";
+ reg = <0x48020000 0x100>;
+ interrupts = <0 74 0x4>;
ti,hwmods = "uart3";
clock-frequency = <48000000>;
};
uart4: serial at 4806e000 {
compatible = "ti,omap4-uart";
+ reg = <0x4806e000 0x100>;
+ interrupts = <0 70 0x4>;
ti,hwmods = "uart4";
clock-frequency = <48000000>;
};
uart5: serial at 48066000 {
- compatible = "ti,omap5-uart";
+ compatible = "ti,omap4-uart";
+ reg = <0x48066000 0x100>;
+ interrupts = <0 105 0x4>;
ti,hwmods = "uart5";
clock-frequency = <48000000>;
};
uart6: serial at 48068000 {
- compatible = "ti,omap6-uart";
+ compatible = "ti,omap4-uart";
+ reg = <0x48068000 0x100>;
+ interrupts = <0 106 0x4>;
ti,hwmods = "uart6";
clock-frequency = <48000000>;
};
--
1.7.10.4
^ permalink raw reply related
* [PATCH 2/4] ARM/dts: omap5: Update I2C with address space and interrupts
From: Sebastien Guiriec @ 2012-10-22 10:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350901328-3525-1-git-send-email-s-guiriec@ti.com>
Add base address and interrupt line inside Device Tree data for
OMAP5
Signed-off-by: Sebastien Guiriec <s-guiriec@ti.com>
---
arch/arm/boot/dts/omap5.dtsi | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index 9e39f9f..6c22e1b 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -192,6 +192,8 @@
i2c1: i2c at 48070000 {
compatible = "ti,omap4-i2c";
+ reg = <0x48070000 0x100>;
+ interrupts = <0 56 0x4>;
#address-cells = <1>;
#size-cells = <0>;
ti,hwmods = "i2c1";
@@ -199,6 +201,8 @@
i2c2: i2c at 48072000 {
compatible = "ti,omap4-i2c";
+ reg = <0x48072000 0x100>;
+ interrupts = <0 57 0x4>;
#address-cells = <1>;
#size-cells = <0>;
ti,hwmods = "i2c2";
@@ -206,20 +210,26 @@
i2c3: i2c at 48060000 {
compatible = "ti,omap4-i2c";
+ reg = <0x48060000 0x100>;
+ interrupts = <0 61 0x4>;
#address-cells = <1>;
#size-cells = <0>;
ti,hwmods = "i2c3";
};
- i2c4: i2c at 4807A000 {
+ i2c4: i2c at 4807a000 {
compatible = "ti,omap4-i2c";
+ reg = <0x4807a000 0x100>;
+ interrupts = <0 62 0x4>;
#address-cells = <1>;
#size-cells = <0>;
ti,hwmods = "i2c4";
};
- i2c5: i2c at 4807C000 {
+ i2c5: i2c at 4807c000 {
compatible = "ti,omap4-i2c";
+ reg = <0x4807c000 0x100>;
+ interrupts = <0 60 0x4>;
#address-cells = <1>;
#size-cells = <0>;
ti,hwmods = "i2c5";
--
1.7.10.4
^ permalink raw reply related
* [PATCH 1/4] ARM/dts: omap5: Update GPIO with address space and interrupt
From: Sebastien Guiriec @ 2012-10-22 10:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350901328-3525-1-git-send-email-s-guiriec@ti.com>
Add base address and interrupt line inside Device Tree data for
OMAP5
Signed-off-by: Sebastien Guiriec <s-guiriec@ti.com>
---
arch/arm/boot/dts/omap5.dtsi | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index 42c78be..9e39f9f 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -104,6 +104,8 @@
gpio1: gpio at 4ae10000 {
compatible = "ti,omap4-gpio";
+ reg = <0x4ae10000 0x200>;
+ interrupts = <0 29 0x4>;
ti,hwmods = "gpio1";
gpio-controller;
#gpio-cells = <2>;
@@ -113,6 +115,8 @@
gpio2: gpio at 48055000 {
compatible = "ti,omap4-gpio";
+ reg = <0x48055000 0x200>;
+ interrupts = <0 30 0x4>;
ti,hwmods = "gpio2";
gpio-controller;
#gpio-cells = <2>;
@@ -122,6 +126,8 @@
gpio3: gpio at 48057000 {
compatible = "ti,omap4-gpio";
+ reg = <0x48057000 0x200>;
+ interrupts = <0 31 0x4>;
ti,hwmods = "gpio3";
gpio-controller;
#gpio-cells = <2>;
@@ -131,6 +137,8 @@
gpio4: gpio at 48059000 {
compatible = "ti,omap4-gpio";
+ reg = <0x48059000 0x200>;
+ interrupts = <0 32 0x4>;
ti,hwmods = "gpio4";
gpio-controller;
#gpio-cells = <2>;
@@ -140,6 +148,8 @@
gpio5: gpio at 4805b000 {
compatible = "ti,omap4-gpio";
+ reg = <0x4805b000 0x200>;
+ interrupts = <0 33 0x4>;
ti,hwmods = "gpio5";
gpio-controller;
#gpio-cells = <2>;
@@ -149,6 +159,8 @@
gpio6: gpio at 4805d000 {
compatible = "ti,omap4-gpio";
+ reg = <0x4805d000 0x200>;
+ interrupts = <0 34 0x4>;
ti,hwmods = "gpio6";
gpio-controller;
#gpio-cells = <2>;
@@ -158,6 +170,8 @@
gpio7: gpio at 48051000 {
compatible = "ti,omap4-gpio";
+ reg = <0x48051000 0x200>;
+ interrupts = <0 35 0x4>;
ti,hwmods = "gpio7";
gpio-controller;
#gpio-cells = <2>;
@@ -167,6 +181,8 @@
gpio8: gpio at 48053000 {
compatible = "ti,omap4-gpio";
+ reg = <0x48053000 0x200>;
+ interrupts = <0 121 0x4>;
ti,hwmods = "gpio8";
gpio-controller;
#gpio-cells = <2>;
--
1.7.10.4
^ permalink raw reply related
* [PATCH 0/4] ARM/dts: Update OMAP5 with address space and interrupts
From: Sebastien Guiriec @ 2012-10-22 10:22 UTC (permalink / raw)
To: linux-arm-kernel
Since kernel 3.7 the DTS data are not overwriten by hwmod data we can add the address space
and interrupt line description inside dtsi file for OMAP5. This serie is updating the
current OMAP5 IP with missing entry.
It has been tested on OMAP5 with 3.7-audio-display feature tree.
- MMC is probing and functional
- TWL6041 probing (GPIO/I2C)
- booting (UART)
Sebastien Guiriec (4):
ARM/dts: omap5: Update GPIO with address space and interrupt
ARM/dts: omap5: Update I2C with address space and interrupts
ARM/dts: omap5: Update UART with address space and interrupts
ARM/dts: omap5: Update MMC with address space and interrupts
arch/arm/boot/dts/omap5.dtsi | 56 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 52 insertions(+), 4 deletions(-)
--
1.7.10.4
^ permalink raw reply
* [PATCH 5/5] ASoC: sam9g20_wm8731: fix the issue for non-DT kernel
From: Bo Shen @ 2012-10-22 10:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350901079-18307-1-git-send-email-voice.shen@atmel.com>
When register platform from DAIs, the platform device to PCM no longer
needed. So, fix it with this patch
Signed-off-by: Bo Shen <voice.shen@atmel.com>
---
arch/arm/mach-at91/board-sam9g20ek.c | 6 ------
sound/soc/atmel/sam9g20_wm8731.c | 2 +-
2 files changed, 1 insertion(+), 7 deletions(-)
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
index 5b6a6f9..ebdbf42 100644
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ b/arch/arm/mach-at91/board-sam9g20ek.c
@@ -353,11 +353,6 @@ static struct i2c_board_info __initdata ek_i2c_devices[] = {
},
};
-static struct platform_device sam9g20ek_pcm_device = {
- .name = "atmel-pcm-audio",
- .id = -1,
-};
-
static struct platform_device sam9g20ek_audio_device = {
.name = "at91sam9g20ek-audio",
.id = -1,
@@ -365,7 +360,6 @@ static struct platform_device sam9g20ek_audio_device = {
static void __init ek_add_device_audio(void)
{
- platform_device_register(&sam9g20ek_pcm_device);
platform_device_register(&sam9g20ek_audio_device);
}
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index 187dc65..0c5987a 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -182,7 +182,7 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = {
.cpu_dai_name = "atmel-ssc-dai.0",
.codec_dai_name = "wm8731-hifi",
.init = at91sam9g20ek_wm8731_init,
- .platform_name = "atmel-pcm-audio",
+ .platform_name = "atmel-ssc-dai.0",
.codec_name = "wm8731.0-001b",
.ops = &at91sam9g20ek_ops,
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH 4/5] ASoC: sam9g20_wm8731: convert to device tree support
From: Bo Shen @ 2012-10-22 10:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350901079-18307-1-git-send-email-voice.shen@atmel.com>
Covert sam9g20 wm8731 to device tree support
And enable it through dts file
Tested on sam9g20 EK board
Signed-off-by: Bo Shen <voice.shen@atmel.com>
---
arch/arm/boot/dts/at91sam9g20ek_common.dtsi | 25 +++++++++++--
sound/soc/atmel/Kconfig | 2 +-
sound/soc/atmel/sam9g20_wm8731.c | 51 +++++++++++++++++++++++++--
3 files changed, 73 insertions(+), 5 deletions(-)
diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
index b06c0db..056ff33 100644
--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
@@ -51,6 +51,10 @@
atmel,vbus-gpio = <&pioC 5 0>;
status = "okay";
};
+
+ ssc0: ssc at fffbc000 {
+ status = "okay";
+ };
};
nand0: nand at 40000000 {
@@ -114,8 +118,8 @@
reg = <0x50>;
};
- wm8731 at 1b {
- compatible = "wm8731";
+ wm8731: wm8731 at 1b {
+ compatible = "wlf,wm8731";
reg = <0x1b>;
};
};
@@ -139,4 +143,21 @@
gpio-key,wakeup;
};
};
+
+ dai: dai {
+ compatible = "atmel,atmel-ssc-dai";
+ atmel,dai-master = <&ssc0>;
+ };
+
+ sound {
+ compatible = "atmel,at91sam9g20-audio";
+ atmel,model = "wm8731 @ sam9g20ek";
+
+ atmel,audio-routing =
+ "Ext Spk", "LHPOUT",
+ "Int Mic", "MICIN";
+
+ atmel,audio-codec = <&wm8731>;
+ atmel,dai = <&dai>;
+ };
};
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index 72b09cf..43a82f0 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -16,7 +16,7 @@ config SND_ATMEL_SOC_SSC
config SND_AT91_SOC_SAM9G20_WM8731
tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
- depends on ATMEL_SSC && ARCH_AT91SAM9G20 && SND_ATMEL_SOC && \
+ depends on ATMEL_SSC && SND_ATMEL_SOC && \
AT91_PROGRAMMABLE_CLOCKS
select SND_ATMEL_SOC_SSC
select SND_SOC_WM8731
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index e5e27db..187dc65 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -197,13 +197,17 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = {
static int __devinit at91sam9g20ek_audio_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *codec_np, *cpu_np;
struct clk *pllb;
struct snd_soc_card *card =&snd_soc_at91sam9g20ek;
int ret;
- if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc()))
+ if (!np) {
+ if (!(machine_is_at91sam9g20ek()
+ || machine_is_at91sam9g20ek_2mmc()))
return -ENODEV;
-
+ }
/*
* Codec MCLK is supplied by PCK0 - set it up.
*/
@@ -230,6 +234,40 @@ static int __devinit at91sam9g20ek_audio_probe(struct platform_device *pdev)
clk_set_rate(mclk, MCLK_RATE);
card->dev = &pdev->dev;
+
+ /* Parse device node info */
+ if (np) {
+ ret = snd_soc_of_parse_card_name(card, "atmel,model");
+ if (ret)
+ goto err;
+
+ ret = snd_soc_of_parse_audio_routing(card,
+ "atmel,audio-routing");
+ if (ret)
+ goto err;
+
+ /* Parse codec dai info */
+ at91sam9g20ek_dai.codec_name = NULL;
+ codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
+ if (!codec_np) {
+ dev_err(&pdev->dev, "codec info missing\n");
+ return -EINVAL;
+ }
+ at91sam9g20ek_dai.codec_of_node = codec_np;
+ at91sam9g20ek_dai.cpu_dai_name = NULL;
+ at91sam9g20ek_dai.platform_name = NULL;
+ cpu_np = of_parse_phandle(np, "atmel,dai", 0);
+ if (!cpu_np) {
+ dev_err(&pdev->dev, "dai info missing\n");
+ return -EINVAL;
+ }
+ at91sam9g20ek_dai.cpu_of_node = cpu_np;
+ at91sam9g20ek_dai.platform_of_node = cpu_np;
+
+ of_node_put(codec_np);
+ of_node_put(cpu_np);
+ }
+
ret = snd_soc_register_card(card);
if (ret) {
printk(KERN_ERR "ASoC: snd_soc_register_card() failed\n");
@@ -255,10 +293,19 @@ static int __devexit at91sam9g20ek_audio_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_wm8731_dt_ids[] = {
+ { .compatible = "atmel,at91sam9g20-audio", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, atmel_wm8731_dt_ids);
+#endif
+
static struct platform_driver at91sam9g20ek_audio_driver = {
.driver = {
.name = "at91sam9g20ek-audio",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(atmel_wm8731_dt_ids),
},
.probe = at91sam9g20ek_audio_probe,
.remove = __devexit_p(at91sam9g20ek_audio_remove),
--
1.7.9.5
^ permalink raw reply related
* [PATCH 3/5] ASoC: atmel-ssc-dai: register 'platform' from DAIs
From: Bo Shen @ 2012-10-22 10:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350901079-18307-1-git-send-email-voice.shen@atmel.com>
Register platform from DAIs
Although we have different number of SSC, but
the one use for audio only need request when dai driver run probe
function. So, remove the redundant code.
Signed-off-by: Bo Shen <voice.shen@atmel.com>
---
sound/soc/atmel/atmel-pcm.c | 23 +---
sound/soc/atmel/atmel-pcm.h | 3 +
sound/soc/atmel/atmel_ssc_dai.c | 248 ++++++++++++---------------------------
3 files changed, 81 insertions(+), 193 deletions(-)
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index 9b84f98..1e9cd2c 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -473,28 +473,17 @@ static struct snd_soc_platform_driver atmel_soc_platform = {
.resume = atmel_pcm_resume,
};
-static int __devinit atmel_soc_platform_probe(struct platform_device *pdev)
+int __devinit atmel_pcm_platform_register(struct device *dev)
{
- return snd_soc_register_platform(&pdev->dev, &atmel_soc_platform);
+ return snd_soc_register_platform(dev, &atmel_soc_platform);
}
+EXPORT_SYMBOL(atmel_pcm_platform_register);
-static int __devexit atmel_soc_platform_remove(struct platform_device *pdev)
+void __devexit atmel_pcm_platform_unregister(struct device *dev)
{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
+ snd_soc_unregister_platform(dev);
}
-
-static struct platform_driver atmel_pcm_driver = {
- .driver = {
- .name = "atmel-pcm-audio",
- .owner = THIS_MODULE,
- },
-
- .probe = atmel_soc_platform_probe,
- .remove = __devexit_p(atmel_soc_platform_remove),
-};
-
-module_platform_driver(atmel_pcm_driver);
+EXPORT_SYMBOL(atmel_pcm_platform_unregister);
MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
MODULE_DESCRIPTION("Atmel PCM module");
diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h
index 5e0a95e..2d1c60f 100644
--- a/sound/soc/atmel/atmel-pcm.h
+++ b/sound/soc/atmel/atmel-pcm.h
@@ -80,4 +80,7 @@ struct atmel_pcm_dma_params {
#define ssc_readx(base, reg) (__raw_readl((base) + (reg)))
#define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg))
+int __devexit atmel_pcm_platform_register(struct device *dev);
+void __devexit atmel_pcm_platform_unregister(struct device *dev);
+
#endif /* _ATMEL_PCM_H */
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 354341e..4436e09 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -42,18 +42,13 @@
#include <sound/initval.h>
#include <sound/soc.h>
+#include <linux/of.h>
+
#include <mach/hardware.h>
#include "atmel-pcm.h"
#include "atmel_ssc_dai.h"
-
-#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)
-#define NUM_SSC_DEVICES 1
-#else
-#define NUM_SSC_DEVICES 3
-#endif
-
/*
* SSC PDC registers required by the PCM DMA engine.
*/
@@ -96,63 +91,24 @@ static struct atmel_ssc_mask ssc_rx_mask = {
/*
* DMA parameters.
*/
-static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
- {{
- .name = "SSC0 PCM out",
- .pdc = &pdc_tx_reg,
- .mask = &ssc_tx_mask,
- },
+static struct atmel_pcm_dma_params ssc_dma_params[2] = {
{
- .name = "SSC0 PCM in",
- .pdc = &pdc_rx_reg,
- .mask = &ssc_rx_mask,
- } },
-#if NUM_SSC_DEVICES == 3
- {{
- .name = "SSC1 PCM out",
+ .name = "SSC PCM out",
.pdc = &pdc_tx_reg,
.mask = &ssc_tx_mask,
},
{
- .name = "SSC1 PCM in",
+ .name = "SSC PCM in",
.pdc = &pdc_rx_reg,
.mask = &ssc_rx_mask,
- } },
- {{
- .name = "SSC2 PCM out",
- .pdc = &pdc_tx_reg,
- .mask = &ssc_tx_mask,
},
- {
- .name = "SSC2 PCM in",
- .pdc = &pdc_rx_reg,
- .mask = &ssc_rx_mask,
- } },
-#endif
};
-
-static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
- {
- .name = "ssc0",
+static struct atmel_ssc_info ssc_info = {
+ .name = "ssc",
.lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock),
.dir_mask = SSC_DIR_MASK_UNUSED,
.initialized = 0,
- },
-#if NUM_SSC_DEVICES == 3
- {
- .name = "ssc1",
- .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock),
- .dir_mask = SSC_DIR_MASK_UNUSED,
- .initialized = 0,
- },
- {
- .name = "ssc2",
- .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock),
- .dir_mask = SSC_DIR_MASK_UNUSED,
- .initialized = 0,
- },
-#endif
};
@@ -205,7 +161,7 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
static int atmel_ssc_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
+ struct atmel_ssc_info *ssc_p = &ssc_info;
int dir_mask;
pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
@@ -234,7 +190,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
+ struct atmel_ssc_info *ssc_p = &ssc_info;
struct atmel_pcm_dma_params *dma_params;
int dir, dir_mask;
@@ -285,7 +241,7 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
+ struct atmel_ssc_info *ssc_p = &ssc_info;
ssc_p->daifmt = fmt;
return 0;
@@ -297,7 +253,7 @@ static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
int div_id, int div)
{
- struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
+ struct atmel_ssc_info *ssc_p = &ssc_info;
switch (div_id) {
case ATMEL_SSC_CMR_DIV:
@@ -336,8 +292,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
- int id = dai->id;
- struct atmel_ssc_info *ssc_p = &ssc_info[id];
+ struct atmel_ssc_info *ssc_p = &ssc_info;
struct atmel_pcm_dma_params *dma_params;
int dir, channels, bits;
u32 tfmr, rfmr, tcmr, rcmr;
@@ -354,7 +309,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
else
dir = 1;
- dma_params = &ssc_dma_params[id][dir];
+ dma_params = &ssc_dma_params[dir];
dma_params->ssc = ssc_p->ssc;
dma_params->substream = substream;
@@ -603,7 +558,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
+ struct atmel_ssc_info *ssc_p = &ssc_info;
struct atmel_pcm_dma_params *dma_params;
int dir;
@@ -631,7 +586,7 @@ static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai)
if (!cpu_dai->active)
return 0;
- ssc_p = &ssc_info[cpu_dai->id];
+ ssc_p = &ssc_info;
/* Save the status register before disabling transmit and receive */
ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR);
@@ -660,7 +615,7 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
if (!cpu_dai->active)
return 0;
- ssc_p = &ssc_info[cpu_dai->id];
+ ssc_p = &ssc_info;
/* restore SSC register settings */
ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr);
@@ -689,31 +644,14 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
static int atmel_ssc_probe(struct snd_soc_dai *dai)
{
- struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
+ struct atmel_ssc_info *ssc_p = &ssc_info;
int ret = 0;
snd_soc_dai_set_drvdata(dai, ssc_p);
- /*
- * Request SSC device
- */
- ssc_p->ssc = ssc_request(dai->id);
- if (IS_ERR(ssc_p->ssc)) {
- printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id);
- ret = PTR_ERR(ssc_p->ssc);
- }
-
return ret;
}
-static int atmel_ssc_remove(struct snd_soc_dai *dai)
-{
- struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai);
-
- ssc_free(ssc_p->ssc);
- return 0;
-}
-
#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
@@ -728,11 +666,9 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
.set_clkdiv = atmel_ssc_set_dai_clkdiv,
};
-static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
- {
- .name = "atmel-ssc-dai.0",
+static struct snd_soc_dai_driver atmel_ssc_dai = {
+ .name = "atmel-ssc-dai",
.probe = atmel_ssc_probe,
- .remove = atmel_ssc_remove,
.suspend = atmel_ssc_suspend,
.resume = atmel_ssc_resume,
.playback = {
@@ -746,119 +682,79 @@ static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
.rates = ATMEL_SSC_RATES,
.formats = ATMEL_SSC_FORMATS,},
.ops = &atmel_ssc_dai_ops,
- },
-#if NUM_SSC_DEVICES == 3
- {
- .name = "atmel-ssc-dai.1",
- .probe = atmel_ssc_probe,
- .remove = atmel_ssc_remove,
- .suspend = atmel_ssc_suspend,
- .resume = atmel_ssc_resume,
- .playback = {
- .channels_min = 1,
- .channels_max = 2,
- .rates = ATMEL_SSC_RATES,
- .formats = ATMEL_SSC_FORMATS,},
- .capture = {
- .channels_min = 1,
- .channels_max = 2,
- .rates = ATMEL_SSC_RATES,
- .formats = ATMEL_SSC_FORMATS,},
- .ops = &atmel_ssc_dai_ops,
- },
- {
- .name = "atmel-ssc-dai.2",
- .probe = atmel_ssc_probe,
- .remove = atmel_ssc_remove,
- .suspend = atmel_ssc_suspend,
- .resume = atmel_ssc_resume,
- .playback = {
- .channels_min = 1,
- .channels_max = 2,
- .rates = ATMEL_SSC_RATES,
- .formats = ATMEL_SSC_FORMATS,},
- .capture = {
- .channels_min = 1,
- .channels_max = 2,
- .rates = ATMEL_SSC_RATES,
- .formats = ATMEL_SSC_FORMATS,},
- .ops = &atmel_ssc_dai_ops,
- },
-#endif
};
static __devinit int asoc_ssc_probe(struct platform_device *pdev)
{
- BUG_ON(pdev->id < 0);
- BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai));
- return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]);
+ int ret, id;
+
+ if (pdev->dev.of_node) {
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *dai_master_np;
+
+ dai_master_np = of_parse_phandle(np, "atmel,dai-master", 0);
+ if (!dai_master_np) {
+ dev_err(&pdev->dev, "No SSC for atmel dai");
+ return -EINVAL;
+ }
+
+ id = of_alias_get_id(dai_master_np, "ssc");
+ } else {
+ id = to_platform_device(pdev->dev.parent)->id;
+ }
+
+ ssc_info.ssc = ssc_request(id);
+ if (IS_ERR(ssc_info.ssc)) {
+ dev_err(&pdev->dev, "Failed to request SSC %d\n", id);
+ return PTR_ERR(ssc_info.ssc);
+ }
+
+ ret = snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+ goto err_unregister_dai;
+ }
+
+ ret = atmel_pcm_platform_register(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+ goto err;
+ };
+
+ return 0;
+
+err_unregister_dai:
+ snd_soc_unregister_dai(&pdev->dev);
+err:
+ return ret;
}
static int __devexit asoc_ssc_remove(struct platform_device *pdev)
{
+ atmel_pcm_platform_unregister(&pdev->dev);
snd_soc_unregister_dai(&pdev->dev);
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_ssc_dai_dt_ids[] = {
+ { .compatible = "atmel,atmel-ssc-dai", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, atmel_ssc_dai_dt_ids);
+#endif
+
static struct platform_driver asoc_ssc_driver = {
.driver = {
- .name = "atmel-ssc-dai",
- .owner = THIS_MODULE,
+ .name = "atmel-ssc-dai",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(atmel_ssc_dai_dt_ids),
},
.probe = asoc_ssc_probe,
.remove = __devexit_p(asoc_ssc_remove),
};
-/**
- * atmel_ssc_set_audio - Allocate the specified SSC for audio use.
- */
-int atmel_ssc_set_audio(int ssc_id)
-{
- struct ssc_device *ssc;
- static struct platform_device *dma_pdev;
- struct platform_device *ssc_pdev;
- int ret;
-
- if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai))
- return -EINVAL;
-
- /* Allocate a dummy device for DMA if we don't have one already */
- if (!dma_pdev) {
- dma_pdev = platform_device_alloc("atmel-pcm-audio", -1);
- if (!dma_pdev)
- return -ENOMEM;
-
- ret = platform_device_add(dma_pdev);
- if (ret < 0) {
- platform_device_put(dma_pdev);
- dma_pdev = NULL;
- return ret;
- }
- }
-
- ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
- if (!ssc_pdev)
- return -ENOMEM;
-
- /* If we can grab the SSC briefly to parent the DAI device off it */
- ssc = ssc_request(ssc_id);
- if (IS_ERR(ssc))
- pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n",
- PTR_ERR(ssc));
- else {
- ssc_pdev->dev.parent = &(ssc->pdev->dev);
- ssc_free(ssc);
- }
-
- ret = platform_device_add(ssc_pdev);
- if (ret < 0)
- platform_device_put(ssc_pdev);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
-
module_platform_driver(asoc_ssc_driver);
/* Module information */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/5] ARM: at91: atmel-ssc: add device tree support
From: Bo Shen @ 2012-10-22 10:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350901079-18307-1-git-send-email-voice.shen@atmel.com>
Add Atmel SSC for device tree support.
Signed-off-by: Bo Shen <voice.shen@atmel.com>
---
.../devicetree/bindings/misc/atmel-ssc.txt | 15 ++++++
arch/arm/boot/dts/at91sam9260.dtsi | 8 ++++
arch/arm/boot/dts/at91sam9263.dtsi | 16 +++++++
arch/arm/boot/dts/at91sam9g45.dtsi | 16 +++++++
arch/arm/boot/dts/at91sam9x5.dtsi | 8 ++++
arch/arm/mach-at91/at91rm9200.c | 3 ++
arch/arm/mach-at91/at91sam9260.c | 1 +
arch/arm/mach-at91/at91sam9261.c | 3 ++
arch/arm/mach-at91/at91sam9263.c | 2 +
arch/arm/mach-at91/at91sam9g45.c | 2 +
arch/arm/mach-at91/at91sam9rl.c | 2 +
arch/arm/mach-at91/at91sam9x5.c | 1 +
drivers/misc/atmel-ssc.c | 48 ++++++++++++++++++--
13 files changed, 122 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/misc/atmel-ssc.txt
diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt
new file mode 100644
index 0000000..ff5ea22
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/atmel-ssc.txt
@@ -0,0 +1,15 @@
+* Atmel SSC driver.
+
+Required properties:
+- compatible: "atmel,at91rm9200_ssc" or "atmel,at91sam9g45_ssc"
+ - atmel,at91rm9200_ssc: support pdc transfer
+ - atmel,at91sam9g45_ssc: support dma transfer
+- reg: Should contain SSC registers location and length
+- interrupts: Should contain SSC interrupt
+
+Example:
+ssc0: ssc at fffbc000 {
+ compatible = "atmel,at91rm9200-ssc";
+ reg = <0xfffbc000 0x4000>;
+ interrupts = <14 4 5>;
+};
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
index d410581..aaa42d8 100644
--- a/arch/arm/boot/dts/at91sam9260.dtsi
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -29,6 +29,7 @@
tcb0 = &tcb0;
tcb1 = &tcb1;
i2c0 = &i2c0;
+ ssc0 = &ssc0;
};
cpus {
cpu at 0 {
@@ -212,6 +213,13 @@
status = "disabled";
};
+ ssc0: ssc at fffbc000 {
+ compatible = "atmel,at91rm9200-ssc";
+ reg = <0xfffbc000 0x4000>;
+ interrupts = <14 4 5>;
+ status = "disable";
+ };
+
adc0: adc at fffe0000 {
compatible = "atmel,at91sam9260-adc";
reg = <0xfffe0000 0x100>;
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index 3e6e5c1..3b721ee 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -25,6 +25,8 @@
gpio4 = &pioE;
tcb0 = &tcb0;
i2c0 = &i2c0;
+ ssc0 = &ssc0;
+ ssc1 = &ssc1;
};
cpus {
cpu at 0 {
@@ -173,6 +175,20 @@
status = "disabled";
};
+ ssc0: ssc at fff98000 {
+ compatible = "atmel,at91rm9200-ssc";
+ reg = <0xfff98000 0x4000>;
+ interrupts = <16 4 5>;
+ status = "disable";
+ };
+
+ ssc1: ssc at fff9c000 {
+ compatible = "atmel,at91rm9200-ssc";
+ reg = <0xfff9c000 0x4000>;
+ interrupts = <17 4 5>;
+ status = "disable";
+ };
+
macb0: ethernet at fffbc000 {
compatible = "cdns,at32ap7000-macb", "cdns,macb";
reg = <0xfffbc000 0x100>;
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index 3add030..cd9af7c 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -31,6 +31,8 @@
tcb1 = &tcb1;
i2c0 = &i2c0;
i2c1 = &i2c1;
+ ssc0 = &ssc0;
+ ssc1 = &ssc1;
};
cpus {
cpu at 0 {
@@ -226,6 +228,20 @@
status = "disabled";
};
+ ssc0: ssc at fff9c000 {
+ compatible = "atmel,at91sam9g45-ssc";
+ reg = <0xfff9c000 0x4000>;
+ interrupts = <16 4 5>;
+ status = "disable";
+ };
+
+ ssc0: ssc at fffa0000 {
+ compatible = "atmel,at91sam9g45-ssc";
+ reg = <0xfffa0000 0x4000>;
+ interrupts = <17 4 5>;
+ status = "disable";
+ };
+
adc0: adc at fffb0000 {
compatible = "atmel,at91sam9260-adc";
reg = <0xfffb0000 0x100>;
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index 03fc136..69667d0 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -30,6 +30,7 @@
i2c0 = &i2c0;
i2c1 = &i2c1;
i2c2 = &i2c2;
+ ssc0 = &ssc0;
};
cpus {
cpu at 0 {
@@ -87,6 +88,13 @@
interrupts = <1 4 7>;
};
+ ssc0: ssc at f0010000 {
+ compatible = "atmel,at91sam9g45-ssc";
+ reg = <0xf0010000 0x4000>;
+ interrupts = <28 4 5>;
+ status = "disable";
+ };
+
tcb0: timer at f8008000 {
compatible = "atmel,at91sam9x5-tcb";
reg = <0xf8008000 0x100>;
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 85d53c5..6d65feb 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -187,6 +187,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.2", &ssc2_clk),
+ CLKDEV_CON_DEV_ID("pclk", "fffd0000.ssc", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "fffd4000.ssc", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "fffd8000.ssc", &ssc2_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index 2c8aab0..54d4aea 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -211,6 +211,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc_clk),
+ CLKDEV_CON_DEV_ID("pclk", "fffbc000.ssc", &ssc_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk),
/* more usart lookup table for DT entries */
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 4e8c56e..5c7a482 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -177,6 +177,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.2", &ssc2_clk),
+ CLKDEV_CON_DEV_ID("pclk", "fffbc000.ssc", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "fffc0000.ssc", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "fffc4000.ssc", &ssc2_clk),
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261", &twi_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk),
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 95a5471..1f523de 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -188,6 +188,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_ID("hclk", &macb_clk),
CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "fff98000.ssc", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "fff9c000.ssc", &ssc1_clk),
CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk),
CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk),
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index f4f96a6..a4282d3 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -241,6 +241,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk),
CLKDEV_CON_DEV_ID("pclk", "at91sam9g45_ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("pclk", "at91sam9g45_ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "fff9c000.ssc", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "fffa0000.ssc", &ssc1_clk),
CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
CLKDEV_CON_DEV_ID(NULL, "atmel_sha", &aestdessha_clk),
CLKDEV_CON_DEV_ID(NULL, "atmel_tdes", &aestdessha_clk),
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index 4110b54..b683fdc 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -186,6 +186,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "fffc0000.ssc", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "fffc4000.ssc", &ssc1_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index e503538..18fbbb2 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -231,6 +231,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk),
CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "f0010000.ssc", &ssc_clk),
CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk),
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
index f40abd8..929d29a 100644
--- a/drivers/misc/atmel-ssc.c
+++ b/drivers/misc/atmel-ssc.c
@@ -18,6 +18,8 @@
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/of.h>
+
/* Serialize access to ssc_list and user count */
static DEFINE_SPINLOCK(user_lock);
static LIST_HEAD(ssc_list);
@@ -29,7 +31,13 @@ struct ssc_device *ssc_request(unsigned int ssc_num)
spin_lock(&user_lock);
list_for_each_entry(ssc, &ssc_list, list) {
- if (ssc->pdev->id == ssc_num) {
+ if (ssc->pdev->dev.of_node) {
+ if (of_alias_get_id(ssc->pdev->dev.of_node, "ssc")
+ == ssc_num) {
+ ssc_valid = 1;
+ break;
+ }
+ } else if (ssc->pdev->id == ssc_num) {
ssc_valid = 1;
break;
}
@@ -88,10 +96,41 @@ static const struct platform_device_id atmel_ssc_devtypes[] = {
}
};
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_ssc_dt_ids[] = {
+ {
+ .compatible = "atmel,at91rm9200-ssc",
+ .data = &at91rm9200_config,
+ }, {
+ .compatible = "atmel,at91sam9g45-ssc",
+ .data = &at91sam9g45_config,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, atmel_ssc_dt_ids);
+#endif
+
+static inline const struct atmel_ssc_platform_data * __init
+ atmel_ssc_get_driver_data(struct platform_device *pdev)
+{
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(atmel_ssc_dt_ids, pdev->dev.of_node);
+ if (match == NULL)
+ return NULL;
+ return match->data;
+ }
+
+ return (struct atmel_ssc_platform_data *)
+ platform_get_device_id(pdev)->driver_data;
+}
+
static int ssc_probe(struct platform_device *pdev)
{
struct resource *regs;
struct ssc_device *ssc;
+ const struct atmel_ssc_platform_data *plat_dat;
ssc = devm_kzalloc(&pdev->dev, sizeof(struct ssc_device), GFP_KERNEL);
if (!ssc) {
@@ -100,8 +139,10 @@ static int ssc_probe(struct platform_device *pdev)
}
ssc->pdev = pdev;
- ssc->pdata = (struct atmel_ssc_platform_data *)
- platform_get_device_id(pdev)->driver_data;
+
+ plat_dat = atmel_ssc_get_driver_data(pdev);
+ if (!plat_dat)
+ return -ENODEV;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
@@ -160,6 +201,7 @@ static struct platform_driver ssc_driver = {
.driver = {
.name = "ssc",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(atmel_ssc_dt_ids),
},
.id_table = atmel_ssc_devtypes,
.probe = ssc_probe,
--
1.7.9.5
^ permalink raw reply related
* [PATCH 1/5] ARM: at91: atmel-ssc: add platform device id table
From: Bo Shen @ 2012-10-22 10:17 UTC (permalink / raw)
To: linux-arm-kernel
Using platform device id to check whether the Atmel SOC support dma for
data transfer
If match "at91rm9200_ssc" which does not support DMA transfer
If match "at91sam9g45_ssc" which support DMA transfer
Signed-off-by: Bo Shen <voice.shen@atmel.com>
---
arch/arm/mach-at91/at91rm9200.c | 6 +++---
arch/arm/mach-at91/at91rm9200_devices.c | 6 +++---
arch/arm/mach-at91/at91sam9260.c | 2 +-
arch/arm/mach-at91/at91sam9260_devices.c | 2 +-
arch/arm/mach-at91/at91sam9261.c | 6 +++---
arch/arm/mach-at91/at91sam9261_devices.c | 6 +++---
arch/arm/mach-at91/at91sam9263.c | 4 ++--
arch/arm/mach-at91/at91sam9263_devices.c | 4 ++--
arch/arm/mach-at91/at91sam9g45.c | 4 ++--
arch/arm/mach-at91/at91sam9g45_devices.c | 4 ++--
arch/arm/mach-at91/at91sam9rl.c | 4 ++--
arch/arm/mach-at91/at91sam9rl_devices.c | 4 ++--
drivers/misc/atmel-ssc.c | 23 +++++++++++++++++++++++
include/linux/atmel-ssc.h | 5 +++++
14 files changed, 54 insertions(+), 26 deletions(-)
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index b4f0565..85d53c5 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -184,9 +184,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk),
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+ CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.2", &ssc2_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index a563189..59ceea1 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -752,7 +752,7 @@ static struct resource ssc0_resources[] = {
};
static struct platform_device at91rm9200_ssc0_device = {
- .name = "ssc",
+ .name = "at91rm9200_ssc",
.id = 0,
.dev = {
.dma_mask = &ssc0_dmamask,
@@ -794,7 +794,7 @@ static struct resource ssc1_resources[] = {
};
static struct platform_device at91rm9200_ssc1_device = {
- .name = "ssc",
+ .name = "at91rm9200_ssc",
.id = 1,
.dev = {
.dma_mask = &ssc1_dmamask,
@@ -836,7 +836,7 @@ static struct resource ssc2_resources[] = {
};
static struct platform_device at91rm9200_ssc2_device = {
- .name = "ssc",
+ .name = "at91rm9200_ssc",
.id = 2,
.dev = {
.dma_mask = &ssc2_dmamask,
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index ad29f93..2c8aab0 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -210,7 +210,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk),
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
+ CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk),
/* more usart lookup table for DT entries */
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 805ef95..9cfdc3f 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -742,7 +742,7 @@ static struct resource ssc_resources[] = {
};
static struct platform_device at91sam9260_ssc_device = {
- .name = "ssc",
+ .name = "at91rm9200_ssc",
.id = 0,
.dev = {
.dma_mask = &ssc_dmamask,
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 8d999eb..4e8c56e 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -174,9 +174,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+ CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.2", &ssc2_clk),
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261", &twi_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk),
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 9752f17..299637f 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -706,7 +706,7 @@ static struct resource ssc0_resources[] = {
};
static struct platform_device at91sam9261_ssc0_device = {
- .name = "ssc",
+ .name = "at91rm9200_ssc",
.id = 0,
.dev = {
.dma_mask = &ssc0_dmamask,
@@ -748,7 +748,7 @@ static struct resource ssc1_resources[] = {
};
static struct platform_device at91sam9261_ssc1_device = {
- .name = "ssc",
+ .name = "at91rm9200_ssc",
.id = 1,
.dev = {
.dma_mask = &ssc1_dmamask,
@@ -790,7 +790,7 @@ static struct resource ssc2_resources[] = {
};
static struct platform_device at91sam9261_ssc2_device = {
- .name = "ssc",
+ .name = "at91rm9200_ssc",
.id = 2,
.dev = {
.dma_mask = &ssc2_dmamask,
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 6a01d03..95a5471 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -186,8 +186,8 @@ static struct clk *periph_clocks[] __initdata = {
static struct clk_lookup periph_clocks_lookups[] = {
/* One additional fake clock for macb_hclk */
CLKDEV_CON_ID("hclk", &macb_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk),
CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk),
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index 8dde220..df89a00 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -1199,7 +1199,7 @@ static struct resource ssc0_resources[] = {
};
static struct platform_device at91sam9263_ssc0_device = {
- .name = "ssc",
+ .name = "at91rm9200_ssc",
.id = 0,
.dev = {
.dma_mask = &ssc0_dmamask,
@@ -1241,7 +1241,7 @@ static struct resource ssc1_resources[] = {
};
static struct platform_device at91sam9263_ssc1_device = {
- .name = "ssc",
+ .name = "at91rm9200_ssc",
.id = 1,
.dev = {
.dma_mask = &ssc1_dmamask,
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index 84af1b5..f4f96a6 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -239,8 +239,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi0_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "at91sam9g45_ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "at91sam9g45_ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
CLKDEV_CON_DEV_ID(NULL, "atmel_sha", &aestdessha_clk),
CLKDEV_CON_DEV_ID(NULL, "atmel_tdes", &aestdessha_clk),
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index b159607..27e3bf6 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -1459,7 +1459,7 @@ static struct resource ssc0_resources[] = {
};
static struct platform_device at91sam9g45_ssc0_device = {
- .name = "ssc",
+ .name = "at91sam9g45_ssc",
.id = 0,
.dev = {
.dma_mask = &ssc0_dmamask,
@@ -1501,7 +1501,7 @@ static struct resource ssc1_resources[] = {
};
static struct platform_device at91sam9g45_ssc1_device = {
- .name = "ssc",
+ .name = "at91sam9g45_ssc",
.id = 1,
.dev = {
.dma_mask = &ssc1_dmamask,
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index 72e9084..4110b54 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -184,8 +184,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index d6ca054..01220c7 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -832,7 +832,7 @@ static struct resource ssc0_resources[] = {
};
static struct platform_device at91sam9rl_ssc0_device = {
- .name = "ssc",
+ .name = "at91rm9200_ssc",
.id = 0,
.dev = {
.dma_mask = &ssc0_dmamask,
@@ -874,7 +874,7 @@ static struct resource ssc1_resources[] = {
};
static struct platform_device at91sam9rl_ssc1_device = {
- .name = "ssc",
+ .name = "at91rm9200_ssc",
.id = 1,
.dev = {
.dma_mask = &ssc1_dmamask,
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
index ac00f83..f40abd8 100644
--- a/drivers/misc/atmel-ssc.c
+++ b/drivers/misc/atmel-ssc.c
@@ -68,6 +68,26 @@ void ssc_free(struct ssc_device *ssc)
}
EXPORT_SYMBOL(ssc_free);
+static struct atmel_ssc_platform_data at91rm9200_config = {
+ .use_dma = 0,
+};
+
+static struct atmel_ssc_platform_data at91sam9g45_config = {
+ .use_dma = 1,
+};
+
+static const struct platform_device_id atmel_ssc_devtypes[] = {
+ {
+ .name = "at91rm9200_ssc",
+ .driver_data = (unsigned long) &at91rm9200_config,
+ }, {
+ .name = "at91sam9g45_ssc",
+ .driver_data = (unsigned long) &at91sam9g45_config,
+ }, {
+ /* sentinel */
+ }
+};
+
static int ssc_probe(struct platform_device *pdev)
{
struct resource *regs;
@@ -80,6 +100,8 @@ static int ssc_probe(struct platform_device *pdev)
}
ssc->pdev = pdev;
+ ssc->pdata = (struct atmel_ssc_platform_data *)
+ platform_get_device_id(pdev)->driver_data;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
@@ -139,6 +161,7 @@ static struct platform_driver ssc_driver = {
.name = "ssc",
.owner = THIS_MODULE,
},
+ .id_table = atmel_ssc_devtypes,
.probe = ssc_probe,
.remove = __devexit_p(ssc_remove),
};
diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h
index 4eb3175..1ca0e32 100644
--- a/include/linux/atmel-ssc.h
+++ b/include/linux/atmel-ssc.h
@@ -5,10 +5,15 @@
#include <linux/list.h>
#include <linux/io.h>
+struct atmel_ssc_platform_data {
+ int use_dma;
+};
+
struct ssc_device {
struct list_head list;
void __iomem *regs;
struct platform_device *pdev;
+ struct atmel_ssc_platform_data *pdata;
struct clk *clk;
int user;
int irq;
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2] ARM: SMP_TWD: make setup()/stop() reentrant
From: Linus Walleij @ 2012-10-22 10:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121022051319.GA19107@S2101-09.ap.freescale.net>
On Mon, Oct 22, 2012 at 7:13 AM, Shawn Guo <shawn.guo@linaro.org> wrote:
> I have seen two problems with the patch.
>
> 1. twd_timer_setup() is called on per-cpu path, and initial_setup_called
> should be a per-cpu variable.
OK folded this into my v3 patch. I was not properly multithreaded
in my head...
> 2. When secondary cores get off-line, the clockevent devices for
> the cores will be released. So when they become online, the
> clockevent devices should be registered again.
So that is how it happens. Where is the code releasing all
clock events? I was thinking this would more properly be done
in the .stop() path of the SMP TWD driver?
Right now it's not looking good because it "just so happens"
that the clockevent silently goes away in the cycle where
.stop() is called. :-(
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH v3] ARM: SMP_TWD: make setup()/stop() reentrant
From: Linus Walleij @ 2012-10-22 10:10 UTC (permalink / raw)
To: linux-arm-kernel
From: Linus Walleij <linus.walleij@linaro.org>
It has been brought to my knowledge that the .setup()/.stop()
function pair in the SMP TWD is going to be called from atomic
contexts for CPUs coming and going, and then the
clk_prepare()/clk_unprepare() calls cannot be called
on subsequent .setup()/.stop() iterations. This is however
just the tip of an iceberg as the function pair is not
designed to be reentrant at all.
This change makes the SMP_TWD clock .setup()/.stop() pair reentrant
by splitting the .setup() function in three parts:
- One COMMON part that is executed the first time the first CPU
in the TWD cluster is initialized. This will fetch the TWD
clk for the cluster and prepare+enable it. If no clk is
available it will calibrate the rate instead.
- One part that is executed the FIRST TIME a certain CPU is
brought on-line. This initializes and sets up the clock event
for a certain CPU.
- One part that is executed on every subsequent .setup() call.
This will re-initialize the clock event. This is augmented
to call the clk_enable()/clk_disable() pair properly.
Cc: Shawn Guo <shawn.guo@linaro.org>
Reported-by: Peter Chen <peter.chen@freescale.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v2->v3:
- Split setup() in three parts
- re-register the clock event on every setup()
---
arch/arm/kernel/smp_twd.c | 45 ++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 40 insertions(+), 5 deletions(-)
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index b92d524..73e25e2 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -31,6 +31,8 @@ static void __iomem *twd_base;
static struct clk *twd_clk;
static unsigned long twd_timer_rate;
+static bool common_setup_called;
+static DEFINE_PER_CPU(bool, percpu_setup_called);
static struct clock_event_device __percpu **twd_evt;
static int twd_ppi;
@@ -93,6 +95,8 @@ static void twd_timer_stop(struct clock_event_device *clk)
{
twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
disable_percpu_irq(clk->irq);
+ if (!IS_ERR(twd_clk))
+ clk_disable(twd_clk);
}
#ifdef CONFIG_COMMON_CLK
@@ -264,15 +268,46 @@ static struct clk *twd_get_clock(void)
static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
{
struct clock_event_device **this_cpu_clk;
+ int cpu = smp_processor_id();
- if (!twd_clk)
+ /*
+ * If the basic setup for this CPU has been done before don't
+ * bother with the below.
+ */
+ if (per_cpu(percpu_setup_called, cpu)) {
+ if (!IS_ERR(twd_clk))
+ clk_enable(twd_clk);
+ __raw_writel(0, twd_base + TWD_TIMER_CONTROL);
+ clockevents_register_device(*__this_cpu_ptr(twd_evt));
+ enable_percpu_irq(clk->irq, 0);
+ return 0;
+ }
+ per_cpu(percpu_setup_called, cpu) = true;
+
+ /*
+ * This stuff only need to be done once for the entire TWD cluster
+ * during the runtime of the system.
+ */
+ if (!common_setup_called) {
twd_clk = twd_get_clock();
- if (!IS_ERR_OR_NULL(twd_clk))
- twd_timer_rate = clk_get_rate(twd_clk);
- else
- twd_calibrate_rate();
+ /*
+ * We use IS_ERR_OR_NULL() here, because if the clock stubs
+ * are active we will get a valid clk reference which is
+ * however NULL and will return the rate 0. In that case we
+ * need to calibrate the rate instead.
+ */
+ if (!IS_ERR_OR_NULL(twd_clk))
+ twd_timer_rate = clk_get_rate(twd_clk);
+ else
+ twd_calibrate_rate();
+ }
+ common_setup_called = true;
+ /*
+ * The following is done once per CPU the first time .setup() is
+ * called.
+ */
__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
clk->name = "local_timer";
--
1.7.11.3
^ permalink raw reply related
* [PATCH 08/10] pinctrl: single: support pinconf generic
From: Haojian Zhuang @ 2012-10-22 10:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121019191333.GT4730@atomide.com>
On Sat, Oct 20, 2012 at 3:13 AM, Tony Lindgren <tony@atomide.com> wrote:
> * Haojian Zhuang <haojian.zhuang@gmail.com> [121018 02:08]:
>> Add pinconf generic support with POWER SOURCE, BIAS PULL.
> ...
>
>> + case PIN_CONFIG_POWER_SOURCE:
>> + if (pcs->psmask == PCS_OFF_DISABLED
>> + || pcs->psshift == PCS_OFF_DISABLED)
>> + return -ENOTSUPP;
>> + data &= pcs->psmask;
>> + data = data >> pcs->psshift;
>> + *config = data;
>> + return 0;
>> + break;
>
> Hmm, only slightly related to this patch, mostly a generic
> question to others: Do others have any mux registers with
> status bits for things like PIN_CONFIG_POWER_SOURCE?
>
> I could use PIN_CONFIG_POWER_SOURCE for controlling the PBIAS
> for omap MMC. But there's also a status bit that needs to be
> checked for that. I think there was some other similar mux
> register for USB PHY that has a status register.
>
> So I'm wondering should the checking for status bit be handled
> in the pinctrl consume driver? Or should we have some bindings
> for that?
>
Do you mean that the status register only exists in USB PHY controller or
MMC controller?
If so, could we use regulator framework in USB PHY or MMC driver?
Regards
Haojian
^ permalink raw reply
* RT throttling and suspend/resume (was Re: [PATCH] i2c: omap: revert "i2c: omap: switch to threaded IRQ support")
From: Peter Zijlstra @ 2012-10-22 9:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <87391ahvao.fsf@deeprootsystems.com>
On Fri, 2012-10-19 at 16:54 -0700, Kevin Hilman wrote:
> So I did the same thing for my ARM SoC, and it definitley stops the RT
> throttling.
>
> However, it has the undesriable (IMO) side effect of making timed printk
> output rather unhelpful for debugging suspend/resume since printk time
> stays constant throughout suspend/resume no matter how long you
> sleep. :(
>
> So does that mean we have to choose between useful printk times during
> suspend/resume or functioning IRQ threads during suspend/resume ?
Urgh.. this was not something I considered. This being primarily the
sched_clock infrastructure and such.
So what exactly is the problem with the suspend resume thing (its not
something I've ever debugged), is all you need a clean break between pre
and post suspend, or do you need the actual time the machine was gone?
^ permalink raw reply
* [PATCH 8/8] i2c: omap: implement handling for 'transferred' bytes
From: Felipe Balbi @ 2012-10-22 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350899218-13624-1-git-send-email-balbi@ti.com>
this is important in cases where client driver
wants to know how many bytes were actually
transferred.
There is one trick here: if transfer is completed,
meaning I2C_CNT reaches zero, then ARDY will be
asserted to let SW know that it can program a
new transfer.
When ARDY is asserted, I2C_CNT is reset to the
original value (msg->len), which means that
for a successful message, msg->transferred = msg->len
and we don't need to spend time with a register
read.
In case of NACK condition, however, I2C_CNT will
remain with the end value which is the amount of
data transferred until NACK condition found on the
bus inclusive. In this situation, msg->transferred
needs to be initialized with:
msg->len - read(I2C_CNT) - 1;
This patch implements exactly that handling.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/i2c/busses/i2c-omap.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 8104aa2..f59c8cd 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -594,6 +594,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
goto out;
}
+ msg->transferred = msg->len;
+ wmb();
+
if ((dev->cmd_err & OMAP_I2C_STAT_AL)
|| (dev->cmd_err & OMAP_I2C_STAT_ROVR)
|| (dev->cmd_err & OMAP_I2C_STAT_XUDF)) {
@@ -603,6 +606,15 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
}
if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
+ /* In case of a NACK, we need to check how many bytes we
+ * actually transferred, so we can tell our client driver about
+ * it.
+ *
+ * Let's check it here and overwrite msg->transferred.
+ */
+ w = omap_i2c_read_reg(dev, OMAP_I2C_CNT_REG);
+ msg->transferred = msg->len - w - 1;
+
if (msg->flags & I2C_M_IGNORE_NAK)
return 0;
--
1.8.0.rc0
^ permalink raw reply related
* [PATCH 7/8] i2c: add 'transferred' field to struct i2c_msg
From: Felipe Balbi @ 2012-10-22 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350899218-13624-1-git-send-email-balbi@ti.com>
From: Shubhrajyoti D <shubhrajyoti@ti.com>
In case of a NACK, it's wise to tell our clients
drivers about how many bytes were actually transferred.
Support this by adding an extra field to the struct
i2c_msg which gets incremented the amount of bytes
actually transferred.
Signed-off-by: Shubhrajyoti D <shubhrajyoti@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
include/uapi/linux/i2c.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h
index 0e949cb..4b35c9b 100644
--- a/include/uapi/linux/i2c.h
+++ b/include/uapi/linux/i2c.h
@@ -77,6 +77,7 @@ struct i2c_msg {
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
__u16 len; /* msg length */
+ __u16 transferred; /* actual bytes transferred */
__u8 *buf; /* pointer to msg data */
};
--
1.8.0.rc0
^ permalink raw reply related
* [PATCH 6/8] i2c: omap: wait for transfer completion before sending STP bit
From: Felipe Balbi @ 2012-10-22 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350899218-13624-1-git-send-email-balbi@ti.com>
Later patches will come adding support for
reporting amount of bytes transferred so that
client drivers can count how many bytes are
left to transfer.
This is useful mostly in case of NACKs when
client driver wants to know exactly which
byte got NACKed so it doesn't have to resend
all bytes again.
In order to make that work with OMAP's I2C
controller, we need to prevent sending STP
bit until message is transferred. The reason
behind that is because OMAP_I2C_CNT_REG gets
reset to original value after STP bit is
shifted through I2C_SDA line and that would
prevent us from reading the correct number of
bytes left to transfer.
The full programming model suggested by IP
owner was the following:
- start I2C transfer (without STP bit)
- upon completion or NACK, read I2C_CNT register
- write STP bit to I2C_CON register
- wait for ARDY bit
With this patch we're implementing all steps
except step #2 which will come in a later
patch adding such support.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/i2c/busses/i2c-omap.c | 101 ++++++++++++++++--------------------------
1 file changed, 39 insertions(+), 62 deletions(-)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index c65d526..8104aa2 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -438,9 +438,9 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
/* Enable interrupts */
dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
- OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
- OMAP_I2C_IE_AL) | ((dev->fifo_size) ?
- (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
+ OMAP_I2C_IE_NACK | OMAP_I2C_IE_AL) |
+ ((dev->fifo_size) ? (OMAP_I2C_IE_RDR |
+ OMAP_I2C_IE_XDR) : 0);
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
dev->pscstate = psc;
@@ -470,6 +476,22 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
return 0;
}
+static int omap_i2c_wait_for_ardy(struct omap_i2c_dev *dev)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ while (!(omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_ARDY)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting for access ready\n");
+ return -ETIMEDOUT;
+ }
+ usleep_range(800, 1200);
+ }
+
+ return 0;
+}
+
static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx)
{
u16 buf;
@@ -515,7 +537,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
{
struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
unsigned long timeout;
- int ret;
+ int ret = 0;
u16 w;
dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
@@ -556,35 +578,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
if (!(msg->flags & I2C_M_RD))
w |= OMAP_I2C_CON_TRX;
- if (!dev->b_hw && stop)
- w |= OMAP_I2C_CON_STP;
-
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
/*
- * Don't write stt and stp together on some hardware.
- */
- if (dev->b_hw && stop) {
- unsigned long delay = jiffies + OMAP_I2C_TIMEOUT;
- u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
- while (con & OMAP_I2C_CON_STT) {
- con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
-
- /* Let the user know if i2c is in a bad state */
- if (time_after(jiffies, delay)) {
- dev_err(dev->dev, "controller timed out "
- "waiting for start condition to finish\n");
- return -ETIMEDOUT;
- }
- cpu_relax();
- }
-
- w |= OMAP_I2C_CON_STP;
- w &= ~OMAP_I2C_CON_STT;
- omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
- }
-
- /*
* REVISIT: We should abort the transfer on signals, but the bus goes
* into arbitration and we're currently unable to recover from it.
*/
@@ -594,36 +590,36 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
if (timeout == 0) {
dev_err(dev->dev, "controller timed out\n");
ret = -ETIMEDOUT;
- goto err_i2c_init;
+ omap_i2c_init(dev);
+ goto out;
}
if ((dev->cmd_err & OMAP_I2C_STAT_AL)
|| (dev->cmd_err & OMAP_I2C_STAT_ROVR)
|| (dev->cmd_err & OMAP_I2C_STAT_XUDF)) {
ret = -EIO;
- goto err_i2c_init;
+ omap_i2c_init(dev);
+ goto out;
}
if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
if (msg->flags & I2C_M_IGNORE_NAK)
return 0;
- if (stop) {
- w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
- w |= OMAP_I2C_CON_STP;
- omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
- }
-
ret = -EREMOTEIO;
- goto err;
+ omap_i2c_init(dev);
}
- return 0;
+out:
-err_i2c_init:
- omap_i2c_init(dev);
+ if (stop) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+ w |= OMAP_I2C_CON_STP;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+
+ ret = omap_i2c_wait_for_ardy(dev);
+ }
-err:
return ret;
}
@@ -947,19 +937,6 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
break;
}
- /*
- * ProDB0017052: Clear ARDY bit twice
- */
- if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
- OMAP_I2C_STAT_AL)) {
- omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY |
- OMAP_I2C_STAT_RDR |
- OMAP_I2C_STAT_XRDY |
- OMAP_I2C_STAT_XDR |
- OMAP_I2C_STAT_ARDY));
- break;
- }
-
if (stat & OMAP_I2C_STAT_RDR) {
u8 num_bytes = 1;
--
1.8.0.rc0
^ permalink raw reply related
* [PATCH 5/8] i2c: omap: introduce and use OMAP_I2C_IP_VERSION_3
From: Felipe Balbi @ 2012-10-22 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350899218-13624-1-git-send-email-balbi@ti.com>
on OMAP4+ we want to read IRQSTATUS_RAW register,
instead of IRQSTATUS. The reason being that IRQSTATUS
will only contain the bits which were enabled on
IRQENABLE_SET and that will break when we need to
poll for a certain bit which wasn't enabled as an
IRQ source.
One such case is after we finish converting to
deferred stop bit, we will have to poll for ARDY
bit before returning control for the client driver
in order to prevent us from trying to start a
transfer on a bus which is already busy.
Note, however, that omap-i2c.c needs a big rework
on register definition and register access. Such
work will be done in a separate series of patches.
Cc: Benoit Cousson <b-cousson@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
arch/arm/mach-omap2/i2c.c | 3 ++-
arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 2 +-
drivers/i2c/busses/i2c-omap.c | 26 ++++++++++++++++++++++----
include/linux/i2c-omap.h | 1 +
4 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-omap2/i2c.c b/arch/arm/mach-omap2/i2c.c
index fc57e67..e871928 100644
--- a/arch/arm/mach-omap2/i2c.c
+++ b/arch/arm/mach-omap2/i2c.c
@@ -66,7 +66,8 @@ int omap_i2c_reset(struct omap_hwmod *oh)
u16 i2c_con;
int c = 0;
- if (oh->class->rev == OMAP_I2C_IP_VERSION_2) {
+ if ((oh->class->rev == OMAP_I2C_IP_VERSION_2) ||
+ (oh->class->rev == OMAP_I2C_IP_VERSION_3)) {
i2c_con = OMAP4_I2C_CON_OFFSET;
} else if (oh->class->rev == OMAP_I2C_IP_VERSION_1) {
i2c_con = OMAP2_I2C_CON_OFFSET;
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 652d028..ae9c023 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -1521,7 +1521,7 @@ static struct omap_hwmod_class_sysconfig omap44xx_i2c_sysc = {
static struct omap_hwmod_class omap44xx_i2c_hwmod_class = {
.name = "i2c",
.sysc = &omap44xx_i2c_sysc,
- .rev = OMAP_I2C_IP_VERSION_2,
+ .rev = OMAP_I2C_IP_VERSION_3,
.reset = &omap_i2c_reset,
};
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 6219522..c65d526 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -271,8 +271,18 @@ static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
{
- return __raw_readw(i2c_dev->base +
+ /* if we are OMAP_I2C_IP_VERSION_3, we need to read from
+ * IRQSTATUS_RAW, but write to IRQSTATUS
+ */
+ if ((i2c_dev->dtrev == OMAP_I2C_IP_VERSION_3) &&
+ (reg == OMAP_I2C_STAT_REG)) {
+ return __raw_readw(i2c_dev->base +
+ ((i2c_dev->regs[reg] - 0x04)
+ << i2c_dev->reg_shift));
+ } else {
+ return __raw_readw(i2c_dev->base +
(i2c_dev->regs[reg] << i2c_dev->reg_shift));
+ }
}
static int omap_i2c_init(struct omap_i2c_dev *dev)
@@ -1124,10 +1134,18 @@ omap_i2c_probe(struct platform_device *pdev)
dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
- if (dev->dtrev == OMAP_I2C_IP_VERSION_2)
- dev->regs = (u8 *)reg_map_ip_v2;
- else
+ switch (dev->dtrev) {
+ case OMAP_I2C_IP_VERSION_1:
dev->regs = (u8 *)reg_map_ip_v1;
+ break;
+ case OMAP_I2C_IP_VERSION_2:
+ /* FALLTHROUGH */
+ case OMAP_I2C_IP_VERSION_3:
+ /* FALLTHROUGH */
+ default:
+ dev->regs = (u8 *)reg_map_ip_v2;
+ break;
+ }
pm_runtime_enable(dev->dev);
pm_runtime_set_autosuspend_delay(dev->dev, OMAP_I2C_PM_TIMEOUT);
diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h
index df804ba..84f7355 100644
--- a/include/linux/i2c-omap.h
+++ b/include/linux/i2c-omap.h
@@ -14,6 +14,7 @@
#define OMAP_I2C_IP_VERSION_1 1
#define OMAP_I2C_IP_VERSION_2 2
+#define OMAP_I2C_IP_VERSION_3 3
/* struct omap_i2c_bus_platform_data .flags meanings */
--
1.8.0.rc0
^ permalink raw reply related
* [PATCH 4/8] i2c: omap: also complete() when stat becomes zero
From: Felipe Balbi @ 2012-10-22 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350899218-13624-1-git-send-email-balbi@ti.com>
In case we loop on IRQ handler until stat is
finally zero, we would end up in a situation
where all I2C transfers would misteriously
timeout because we were not calling complete()
in that situation.
Fix the issue by moving omap_i2c_complete_cmd()
call inside the 'out' label.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/i2c/busses/i2c-omap.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index e0eab38..6219522 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -1021,9 +1021,8 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
}
} while (stat);
- omap_i2c_complete_cmd(dev, err);
-
out:
+ omap_i2c_complete_cmd(dev, err);
spin_unlock_irqrestore(&dev->lock, flags);
return IRQ_HANDLED;
--
1.8.0.rc0
^ permalink raw reply related
* [PATCH 3/8] i2c: omap: fix error checking
From: Felipe Balbi @ 2012-10-22 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350899218-13624-1-git-send-email-balbi@ti.com>
It's impossible to have Arbitration Lost,
Read Overflow, and Tranmist Underflow all
asserted at the same time.
Those error conditions are mutually exclusive
so what the code should be doing, instead, is
check each error flag separataly.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/i2c/busses/i2c-omap.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index bea0277..e0eab38 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -587,9 +587,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
goto err_i2c_init;
}
- /* We have an error */
- if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
- OMAP_I2C_STAT_XUDF)) {
+ if ((dev->cmd_err & OMAP_I2C_STAT_AL)
+ || (dev->cmd_err & OMAP_I2C_STAT_ROVR)
+ || (dev->cmd_err & OMAP_I2C_STAT_XUDF)) {
ret = -EIO;
goto err_i2c_init;
}
--
1.8.0.rc0
^ permalink raw reply related
* [PATCH 2/8] i2c: omap: reorder exit path of omap_i2c_xfer_msg()
From: Felipe Balbi @ 2012-10-22 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350899218-13624-1-git-send-email-balbi@ti.com>
just a cleanup patch trying to make exit path
more straightforward. No changes otherwise.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/i2c/busses/i2c-omap.c | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index c07d9c4..bea0277 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -505,6 +505,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
{
struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
unsigned long timeout;
+ int ret;
u16 w;
dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
@@ -582,31 +583,38 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
dev->buf_len = 0;
if (timeout == 0) {
dev_err(dev->dev, "controller timed out\n");
- omap_i2c_init(dev);
- return -ETIMEDOUT;
+ ret = -ETIMEDOUT;
+ goto err_i2c_init;
}
- if (likely(!dev->cmd_err))
- return 0;
-
/* We have an error */
if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
OMAP_I2C_STAT_XUDF)) {
- omap_i2c_init(dev);
- return -EIO;
+ ret = -EIO;
+ goto err_i2c_init;
}
if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
if (msg->flags & I2C_M_IGNORE_NAK)
return 0;
+
if (stop) {
w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
w |= OMAP_I2C_CON_STP;
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
}
- return -EREMOTEIO;
+
+ ret = -EREMOTEIO;
+ goto err;
}
- return -EIO;
+
+ return 0;
+
+err_i2c_init:
+ omap_i2c_init(dev);
+
+err:
+ return ret;
}
--
1.8.0.rc0
^ permalink raw reply related
* [PATCH 1/8] i2c: omap: no need to access platform_device
From: Felipe Balbi @ 2012-10-22 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350899218-13624-1-git-send-email-balbi@ti.com>
PM callbacks pass our device pointer as argument
and we don't need to access the platform_device
just to dereference that down to dev->drvdata.
instead, just use dev_get_drvdata() directly.
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
drivers/i2c/busses/i2c-omap.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index db31eae..c07d9c4 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -1239,8 +1239,7 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_RUNTIME
static int omap_i2c_runtime_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
+ struct omap_i2c_dev *_dev = dev_get_drvdata(dev);
u16 iv;
_dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG);
@@ -1261,8 +1260,7 @@ static int omap_i2c_runtime_suspend(struct device *dev)
static int omap_i2c_runtime_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
+ struct omap_i2c_dev *_dev = dev_get_drvdata(dev);
if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, 0);
--
1.8.0.rc0
^ permalink raw reply related
* [PATCH 0/8] I2C patches for v3.8 merge window
From: Felipe Balbi @ 2012-10-22 9:46 UTC (permalink / raw)
To: linux-arm-kernel
Hi guys,
here's another series for OMAP I2C driver. There are a few cleanups
and one very nice new feature: we can now report how many bytes
we transferred until NACK.
Note that the implemementation for OMAP-I2C turned out to be a
little more complex then I expected, mainly because of the way
I2C_CNT register behaves and because of the very buggy register
usage on that driver.
I have boot tested all patches on beagle xM (3630) and pandaboard
rev A3 (4430), will send boot-logs if anyone wants to see.
All patches are available at [1] if anyone wants an easy way to
test the patches.
[1] git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git i2c-transferred-bytes-on-NACK
Felipe Balbi (7):
i2c: omap: no need to access platform_device
i2c: omap: reorder exit path of omap_i2c_xfer_msg()
i2c: omap: fix error checking
i2c: omap: also complete() when stat becomes zero
i2c: omap: introduce and use OMAP_I2C_IP_VERSION_3
i2c: omap: wait for transfer completion before sending STP bit
i2c: omap: implement handling for 'transferred' bytes
Shubhrajyoti D (1):
i2c: add 'transferred' field to struct i2c_msg
arch/arm/mach-omap2/i2c.c | 3 +-
arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 2 +-
drivers/i2c/busses/i2c-omap.c | 156 ++++++++++++++++-------------
include/linux/i2c-omap.h | 1 +
include/uapi/linux/i2c.h | 1 +
5 files changed, 89 insertions(+), 74 deletions(-)
--
1.8.0.rc0
^ permalink raw reply
* [PATCH 1/2] regulator: gpio-regulator: Allow use of GPIO controlled regulators though DT
From: Mark Brown @ 2012-10-22 9:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121022091355.GE3785@gmail.com>
On Mon, Oct 22, 2012 at 10:13:55AM +0100, Lee Jones wrote:
> On Wed, 17 Oct 2012, Mark Brown wrote:
> > This should really be part of the patch adding the bindings...
> Would you like me to send the patch-set again?
When I said I'd applied the patch that was what I meant.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121022/f75a7fe2/attachment.sig>
^ permalink raw reply
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