[v5,6/6] spi: s3c64xx: add device tree support
diff mbox

Message ID 1342021265-11212-7-git-send-email-thomas.abraham@linaro.org
State New, archived
Headers show

Commit Message

Thomas Abraham July 11, 2012, 3:41 p.m. UTC
Add support for device based discovery.

Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
Acked-by: Jaswinder Singh <jaswinder.singh@linaro.org>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
---
 .../devicetree/bindings/spi/spi-samsung.txt        |  113 ++++++++
 drivers/spi/spi-s3c64xx.c                          |  305 +++++++++++++++++---
 2 files changed, 378 insertions(+), 40 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-samsung.txt

Comments

Kim Kukjin July 12, 2012, 10:38 p.m. UTC | #1
On 07/12/12 00:41, Thomas Abraham wrote:
> Add support for device based discovery.
>
> Signed-off-by: Thomas Abraham<thomas.abraham@linaro.org>
> Acked-by: Jaswinder Singh<jaswinder.singh@linaro.org>
> Acked-by: Grant Likely<grant.likely@secretlab.ca>
> ---
>   .../devicetree/bindings/spi/spi-samsung.txt        |  113 ++++++++
>   drivers/spi/spi-s3c64xx.c                          |  305 +++++++++++++++++---
>   2 files changed, 378 insertions(+), 40 deletions(-)
>   create mode 100644 Documentation/devicetree/bindings/spi/spi-samsung.txt
>

[snip]

> @@ -989,49 +1057,166 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
>   	flush_fifo(sdd);
>   }
>
> +static int __devinit s3c64xx_spi_get_dmares(
> +			struct s3c64xx_spi_driver_data *sdd, bool tx)
> +{
> +	struct platform_device *pdev = sdd->pdev;
> +	struct s3c64xx_spi_dma_data *dma_data;
> +	struct property *prop;
> +	struct resource *res;
> +	char prop_name[15], *chan_str;
> +
> +	if (tx) {
> +		dma_data =&sdd->tx_dma;
> +		dma_data->direction = DMA_TO_DEVICE;
> +		chan_str = "tx";
> +	} else {
> +		dma_data =&sdd->rx_dma;
> +		dma_data->direction = DMA_FROM_DEVICE;
> +		chan_str = "rx";
> +	}
> +
> +	if (!sdd->pdev->dev.of_node) {
> +		res = platform_get_resource(pdev, IORESOURCE_DMA, tx ? 0 : 1);
> +		if (!res) {
> +			dev_err(&pdev->dev, "Unable to get SPI-%s dma "
> +					"resource\n", chan_str);
> +			return -ENXIO;
> +		}
> +		dma_data->dmach = res->start;
> +		return 0;
> +	}
> +
> +	sprintf(prop_name, "%s-dma-channel", chan_str);
> +	prop = of_find_property(pdev->dev.of_node, prop_name, NULL);
> +	if (!prop) {
> +		dev_err(&pdev->dev, "%s dma channel property not specified\n",
> +					chan_str);
> +		return -ENXIO;
> +	}
> +
> +	dma_data->dmach = DMACH_DT_PROP;

Thomas, the DMACH_DT_PROP is available only on pl330 now. So seems occur 
following build error with s3c6400_defconfig.

drivers/spi/spi-s3c64xx.c: In function 's3c64xx_spi_get_dmares':
drivers/spi/spi-s3c64xx.c:1098: error: 'DMACH_DT_PROP' undeclared (first 
use in this function)
drivers/spi/spi-s3c64xx.c:1098: error: (Each undeclared identifier is 
reported only once
drivers/spi/spi-s3c64xx.c:1098: error: for each function it appears in.)
make[3]: *** [drivers/spi/spi-s3c64xx.o] Error 1
make[2]: *** [drivers/spi] Error 2

> +	dma_data->dma_prop = prop;
> +	return 0;
> +}

[snip]

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
Thomas Abraham July 13, 2012, 3:55 a.m. UTC | #2
On 13 July 2012 04:08, Kukjin Kim <kgene.kim@samsung.com> wrote:
> Thomas, the DMACH_DT_PROP is available only on pl330 now. So seems occur
> following build error with s3c6400_defconfig.
>
> drivers/spi/spi-s3c64xx.c: In function 's3c64xx_spi_get_dmares':
> drivers/spi/spi-s3c64xx.c:1098: error: 'DMACH_DT_PROP' undeclared (first use
> in this function)
> drivers/spi/spi-s3c64xx.c:1098: error: (Each undeclared identifier is
> reported only once
> drivers/spi/spi-s3c64xx.c:1098: error: for each function it appears in.)
> make[3]: *** [drivers/spi/spi-s3c64xx.o] Error 1
> make[2]: *** [drivers/spi] Error 2
>

Dear Mr. Kim,

Thanks for considering these patches to be merged via your tree. For
the build break you mentioned above, there was a patch submitted some
time back to handle this. The link to that patch is:
http://lists.infradead.org/pipermail/linux-arm-kernel/2012-June/102627.html.
Could you please apply this patch also to your tree.

Thanks,
Thomas.
Kim Kukjin July 13, 2012, 11:28 a.m. UTC | #3
Thomas Abraham wrote:
> 
> On 13 July 2012 04:08, Kukjin Kim <kgene.kim@samsung.com> wrote:
> > Thomas, the DMACH_DT_PROP is available only on pl330 now. So seems occur
> > following build error with s3c6400_defconfig.
> >
> > drivers/spi/spi-s3c64xx.c: In function 's3c64xx_spi_get_dmares':
> > drivers/spi/spi-s3c64xx.c:1098: error: 'DMACH_DT_PROP' undeclared (first
> use
> > in this function)
> > drivers/spi/spi-s3c64xx.c:1098: error: (Each undeclared identifier is
> > reported only once
> > drivers/spi/spi-s3c64xx.c:1098: error: for each function it appears in.)
> > make[3]: *** [drivers/spi/spi-s3c64xx.o] Error 1
> > make[2]: *** [drivers/spi] Error 2
> >
> 
> Dear Mr. Kim,
> 
> Thanks for considering these patches to be merged via your tree. For
> the build break you mentioned above, there was a patch submitted some
> time back to handle this. The link to that patch is:
> http://lists.infradead.org/pipermail/linux-arm-kernel/2012-
> June/102627.html.
> Could you please apply this patch also to your tree.
> 
Sure, it looks good to me, will apply that then this series will be rebased
on top of that.

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
Thomas Abraham July 13, 2012, 11:38 a.m. UTC | #4
On 13 July 2012 16:58, Kukjin Kim <kgene.kim@samsung.com> wrote:
> Thomas Abraham wrote:
>>
>> On 13 July 2012 04:08, Kukjin Kim <kgene.kim@samsung.com> wrote:
>> > Thomas, the DMACH_DT_PROP is available only on pl330 now. So seems occur
>> > following build error with s3c6400_defconfig.
>> >
>> > drivers/spi/spi-s3c64xx.c: In function 's3c64xx_spi_get_dmares':
>> > drivers/spi/spi-s3c64xx.c:1098: error: 'DMACH_DT_PROP' undeclared (first
>> use
>> > in this function)
>> > drivers/spi/spi-s3c64xx.c:1098: error: (Each undeclared identifier is
>> > reported only once
>> > drivers/spi/spi-s3c64xx.c:1098: error: for each function it appears in.)
>> > make[3]: *** [drivers/spi/spi-s3c64xx.o] Error 1
>> > make[2]: *** [drivers/spi] Error 2
>> >
>>
>> Dear Mr. Kim,
>>
>> Thanks for considering these patches to be merged via your tree. For
>> the build break you mentioned above, there was a patch submitted some
>> time back to handle this. The link to that patch is:
>> http://lists.infradead.org/pipermail/linux-arm-kernel/2012-
>> June/102627.html.
>> Could you please apply this patch also to your tree.
>>
> Sure, it looks good to me, will apply that then this series will be rebased
> on top of that.

There are six more patches that enable spi device tree support for
Exynos4 and Exynos5 platforms. Could you consider to apply those
patches as well. The link to those patches is:
http://www.mail-archive.com/linux-samsung-soc@vger.kernel.org/msg10851.html.

Thanks,
Thomas.
Kim Kukjin July 13, 2012, 1:42 p.m. UTC | #5
Thomas Abraham wrote:
> 
> On 13 July 2012 16:58, Kukjin Kim <kgene.kim@samsung.com> wrote:
> > Thomas Abraham wrote:
> >>
> >> On 13 July 2012 04:08, Kukjin Kim <kgene.kim@samsung.com> wrote:
> >> > Thomas, the DMACH_DT_PROP is available only on pl330 now. So seems
> occur
> >> > following build error with s3c6400_defconfig.
> >> >
> >> > drivers/spi/spi-s3c64xx.c: In function 's3c64xx_spi_get_dmares':
> >> > drivers/spi/spi-s3c64xx.c:1098: error: 'DMACH_DT_PROP' undeclared
> (first
> >> use
> >> > in this function)
> >> > drivers/spi/spi-s3c64xx.c:1098: error: (Each undeclared identifier is
> >> > reported only once
> >> > drivers/spi/spi-s3c64xx.c:1098: error: for each function it appears
> in.)
> >> > make[3]: *** [drivers/spi/spi-s3c64xx.o] Error 1
> >> > make[2]: *** [drivers/spi] Error 2
> >> >
> >>
> >> Dear Mr. Kim,
> >>
> >> Thanks for considering these patches to be merged via your tree. For
> >> the build break you mentioned above, there was a patch submitted some
> >> time back to handle this. The link to that patch is:
> >> http://lists.infradead.org/pipermail/linux-arm-kernel/2012-
> >> June/102627.html.
> >> Could you please apply this patch also to your tree.
> >>
> > Sure, it looks good to me, will apply that then this series will be
> rebased
> > on top of that.
> 
> There are six more patches that enable spi device tree support for
> Exynos4 and Exynos5 platforms. Could you consider to apply those
> patches as well. The link to those patches is:
> http://www.mail-archive.com/linux-samsung-
> soc@vger.kernel.org/msg10851.html.
> 
Yeah, I remember, but I think some patches is needed to re-work as per
comments...?

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
Thomas Abraham July 13, 2012, 2:51 p.m. UTC | #6
On 13 July 2012 19:12, Kukjin Kim <kgene.kim@samsung.com> wrote:
> Thomas Abraham wrote:
>>
>> On 13 July 2012 16:58, Kukjin Kim <kgene.kim@samsung.com> wrote:
>> > Thomas Abraham wrote:
>> >>
>> >> On 13 July 2012 04:08, Kukjin Kim <kgene.kim@samsung.com> wrote:
>> >> > Thomas, the DMACH_DT_PROP is available only on pl330 now. So seems
>> occur
>> >> > following build error with s3c6400_defconfig.
>> >> >
>> >> > drivers/spi/spi-s3c64xx.c: In function 's3c64xx_spi_get_dmares':
>> >> > drivers/spi/spi-s3c64xx.c:1098: error: 'DMACH_DT_PROP' undeclared
>> (first
>> >> use
>> >> > in this function)
>> >> > drivers/spi/spi-s3c64xx.c:1098: error: (Each undeclared identifier is
>> >> > reported only once
>> >> > drivers/spi/spi-s3c64xx.c:1098: error: for each function it appears
>> in.)
>> >> > make[3]: *** [drivers/spi/spi-s3c64xx.o] Error 1
>> >> > make[2]: *** [drivers/spi] Error 2
>> >> >
>> >>
>> >> Dear Mr. Kim,
>> >>
>> >> Thanks for considering these patches to be merged via your tree. For
>> >> the build break you mentioned above, there was a patch submitted some
>> >> time back to handle this. The link to that patch is:
>> >> http://lists.infradead.org/pipermail/linux-arm-kernel/2012-
>> >> June/102627.html.
>> >> Could you please apply this patch also to your tree.
>> >>
>> > Sure, it looks good to me, will apply that then this series will be
>> rebased
>> > on top of that.
>>
>> There are six more patches that enable spi device tree support for
>> Exynos4 and Exynos5 platforms. Could you consider to apply those
>> patches as well. The link to those patches is:
>> http://www.mail-archive.com/linux-samsung-
>> soc@vger.kernel.org/msg10851.html.
>>
> Yeah, I remember, but I think some patches is needed to re-work as per
> comments...?

I checked again for any pending comments on v2 version. There are no
pending comments for the v2 version of this patch series. Thanks.
Kim Kukjin July 15, 2012, 10:39 a.m. UTC | #7
Thomas Abraham wrote:
> 
> On 13 July 2012 19:12, Kukjin Kim <kgene.kim@samsung.com> wrote:
> > Thomas Abraham wrote:
> >>
> >> On 13 July 2012 16:58, Kukjin Kim <kgene.kim@samsung.com> wrote:
> >> > Thomas Abraham wrote:
> >> >>
> >> >> On 13 July 2012 04:08, Kukjin Kim <kgene.kim@samsung.com> wrote:
> >> >> > Thomas, the DMACH_DT_PROP is available only on pl330 now. So seems
> >> occur
> >> >> > following build error with s3c6400_defconfig.
> >> >> >
> >> >> > drivers/spi/spi-s3c64xx.c: In function 's3c64xx_spi_get_dmares':
> >> >> > drivers/spi/spi-s3c64xx.c:1098: error: 'DMACH_DT_PROP' undeclared
> >> (first
> >> >> use
> >> >> > in this function)
> >> >> > drivers/spi/spi-s3c64xx.c:1098: error: (Each undeclared identifier
> is
> >> >> > reported only once
> >> >> > drivers/spi/spi-s3c64xx.c:1098: error: for each function it
> appears
> >> in.)
> >> >> > make[3]: *** [drivers/spi/spi-s3c64xx.o] Error 1
> >> >> > make[2]: *** [drivers/spi] Error 2
> >> >> >
> >> >>
> >> >> Dear Mr. Kim,
> >> >>
> >> >> Thanks for considering these patches to be merged via your tree. For
> >> >> the build break you mentioned above, there was a patch submitted
> some
> >> >> time back to handle this. The link to that patch is:
> >> >> http://lists.infradead.org/pipermail/linux-arm-kernel/2012-
> >> >> June/102627.html.
> >> >> Could you please apply this patch also to your tree.
> >> >>
> >> > Sure, it looks good to me, will apply that then this series will be
> >> rebased
> >> > on top of that.
> >>
> >> There are six more patches that enable spi device tree support for
> >> Exynos4 and Exynos5 platforms. Could you consider to apply those
> >> patches as well. The link to those patches is:
> >> http://www.mail-archive.com/linux-samsung-
> >> soc@vger.kernel.org/msg10851.html.
> >>
> > Yeah, I remember, but I think some patches is needed to re-work as per
> > comments...?
> 
> I checked again for any pending comments on v2 version. There are no
> pending comments for the v2 version of this patch series. Thanks.

OK, I checked v2 series you mentioned. Looks OK to me and applied into
next/dt-samsung because it is related in supporting dt.

Note, I applied all of them into same dt branch, the fist one 'fix the
incorrect hierarchy of spi controller bus clock for exynos4' can be sent to
upstream via fixes now though. And I changed the clock name for
exynos4_clk_mdout_spix to 'mdout_spi' for consensus when I applied.

If any problems, please let me know.

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

Patch
diff mbox

diff --git a/Documentation/devicetree/bindings/spi/spi-samsung.txt b/Documentation/devicetree/bindings/spi/spi-samsung.txt
new file mode 100644
index 0000000..59bfc4f
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-samsung.txt
@@ -0,0 +1,113 @@ 
+* Samsung SPI Controller
+
+The Samsung SPI controller is used to interface with various devices such as flash
+and display controllers using the SPI communication interface.
+
+Required SoC Specific Properties:
+
+- compatible: should be one of the following.
+    - samsung,s3c2443-spi: for s3c2443, s3c2416 and s3c2450 platforms
+    - samsung,s3c6410-spi: for s3c6410 platforms
+    - samsung,s5p6440-spi: for s5p6440 and s5p6450 platforms
+    - samsung,s5pv210-spi: for s5pv210 and s5pc110 platforms
+    - samsung,exynos4210-spi: for exynos4 and exynos5 platforms
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- interrupts: The interrupt number to the cpu. The interrupt specifier format
+  depends on the interrupt controller.
+
+- tx-dma-channel: The dma channel specifier for tx operations. The format of
+  the dma specifier depends on the dma controller.
+
+- rx-dma-channel: The dma channel specifier for rx operations. The format of
+  the dma specifier depends on the dma controller.
+
+Required Board Specific Properties:
+
+- #address-cells: should be 1.
+- #size-cells: should be 0.
+- gpios: The gpio specifier for clock, mosi and miso interface lines (in the
+  order specified). The format of the gpio specifier depends on the gpio
+  controller.
+
+Optional Board Specific Properties:
+
+- samsung,spi-src-clk: If the spi controller includes a internal clock mux to
+  select the clock source for the spi bus clock, this property can be used to
+  indicate the clock to be used for driving the spi bus clock. If not specified,
+  the clock number 0 is used as default.
+
+- num-cs: Specifies the number of chip select lines supported. If
+  not specified, the default number of chip select lines is set to 1.
+
+SPI Controller specific data in SPI slave nodes:
+
+- The spi slave nodes should provide the following information which is required
+  by the spi controller.
+
+  - cs-gpio: A gpio specifier that specifies the gpio line used as
+    the slave select line by the spi controller. The format of the gpio
+    specifier depends on the gpio controller.
+
+  - samsung,spi-feedback-delay: The sampling phase shift to be applied on the
+    miso line (to account for any lag in the miso line). The following are the
+    valid values.
+
+      - 0: No phase shift.
+      - 1: 90 degree phase shift sampling.
+      - 2: 180 degree phase shift sampling.
+      - 3: 270 degree phase shift sampling.
+
+Aliases:
+
+- All the SPI controller nodes should be represented in the aliases node using
+  the following format 'spi{n}' where n is a unique number for the alias.
+
+
+Example:
+
+- SoC Specific Portion:
+
+	spi_0: spi@12d20000 {
+		compatible = "samsung,exynos4210-spi";
+		reg = <0x12d20000 0x100>;
+		interrupts = <0 66 0>;
+		tx-dma-channel = <&pdma0 5>;
+		rx-dma-channel = <&pdma0 4>;
+	};
+
+- Board Specific Portion:
+
+	spi_0: spi@12d20000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		gpios = <&gpa2 4 2 3 0>,
+			<&gpa2 6 2 3 0>,
+			<&gpa2 7 2 3 0>;
+
+		w25q80bw@0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "w25x80";
+			reg = <0>;
+			spi-max-frequency = <10000>;
+
+			controller-data {
+				cs-gpio = <&gpa2 5 1 0 3>;
+				samsung,spi-feedback-delay = <0>;
+			};
+
+			partition@0 {
+				label = "U-Boot";
+				reg = <0x0 0x40000>;
+				read-only;
+			};
+
+			partition@40000 {
+				label = "Kernel";
+				reg = <0x40000 0xc0000>;
+			};
+		};
+	};
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index e4182ea..6c15f05 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -28,6 +28,8 @@ 
 #include <linux/pm_runtime.h>
 #include <linux/spi/spi.h>
 #include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include <mach/dma.h>
 #include <plat/s3c64xx-spi.h>
@@ -137,6 +139,7 @@  struct s3c64xx_spi_dma_data {
 	unsigned		ch;
 	enum dma_data_direction direction;
 	enum dma_ch	dmach;
+	struct property		*dma_prop;
 };
 
 /**
@@ -201,6 +204,7 @@  struct s3c64xx_spi_driver_data {
 	struct samsung_dma_ops		*ops;
 	struct s3c64xx_spi_port_config	*port_conf;
 	unsigned int			port_id;
+	unsigned long			gpios[4];
 };
 
 static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
@@ -326,7 +330,9 @@  static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
 	req.cap = DMA_SLAVE;
 	req.client = &s3c64xx_spi_dma_client;
 
+	req.dt_dmach_prop = sdd->rx_dma.dma_prop;
 	sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req);
+	req.dt_dmach_prop = sdd->tx_dma.dma_prop;
 	sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req);
 
 	return 1;
@@ -819,6 +825,48 @@  static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
 	return 0;
 }
 
+static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
+				struct s3c64xx_spi_driver_data *sdd,
+				struct spi_device *spi)
+{
+	struct s3c64xx_spi_csinfo *cs;
+	struct device_node *slave_np, *data_np;
+	u32 fb_delay = 0;
+
+	slave_np = spi->dev.of_node;
+	if (!slave_np) {
+		dev_err(&spi->dev, "device node not found\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	for_each_child_of_node(slave_np, data_np)
+		if (!strcmp(data_np->name, "controller-data"))
+			break;
+	if (!data_np) {
+		dev_err(&spi->dev, "child node 'controller-data' not found\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	cs = kzalloc(sizeof(*cs), GFP_KERNEL);
+	if (!cs) {
+		dev_err(&spi->dev, "could not allocate memory for controller"
+					" data\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	cs->line = of_get_named_gpio(data_np, "cs-gpio", 0);
+	if (!gpio_is_valid(cs->line)) {
+		dev_err(&spi->dev, "chip select gpio is not specified or "
+					"invalid\n");
+		kfree(cs);
+		return ERR_PTR(-EINVAL);
+	}
+
+	of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay);
+	cs->fb_delay = fb_delay;
+	return cs;
+}
+
 /*
  * Here we only check the validity of requested configuration
  * and save the configuration in a local data-structure.
@@ -832,9 +880,15 @@  static int s3c64xx_spi_setup(struct spi_device *spi)
 	struct s3c64xx_spi_info *sci;
 	struct spi_message *msg;
 	unsigned long flags;
-	int err = 0;
+	int err;
 
-	if (cs == NULL) {
+	sdd = spi_master_get_devdata(spi->master);
+	if (!cs && spi->dev.of_node) {
+		cs = s3c64xx_get_slave_ctrldata(sdd, spi);
+		spi->controller_data = cs;
+	}
+
+	if (IS_ERR_OR_NULL(cs)) {
 		dev_err(&spi->dev, "No CS for SPI(%d)\n", spi->chip_select);
 		return -ENODEV;
 	}
@@ -844,12 +898,12 @@  static int s3c64xx_spi_setup(struct spi_device *spi)
 		if (err) {
 			dev_err(&spi->dev, "request for slave select gpio "
 					"line [%d] failed\n", cs->line);
-			return -EBUSY;
+			err = -EBUSY;
+			goto err_gpio_req;
 		}
 		spi_set_ctldata(spi, cs);
 	}
 
-	sdd = spi_master_get_devdata(spi->master);
 	sci = sdd->cntrlr_info;
 
 	spin_lock_irqsave(&sdd->lock, flags);
@@ -860,7 +914,8 @@  static int s3c64xx_spi_setup(struct spi_device *spi)
 			dev_err(&spi->dev,
 				"setup: attempt while mssg in queue!\n");
 			spin_unlock_irqrestore(&sdd->lock, flags);
-			return -EBUSY;
+			err = -EBUSY;
+			goto err_msgq;
 		}
 	}
 
@@ -903,19 +958,29 @@  static int s3c64xx_spi_setup(struct spi_device *spi)
 		}
 
 		speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
-		if (spi->max_speed_hz >= speed)
+		if (spi->max_speed_hz >= speed) {
 			spi->max_speed_hz = speed;
-		else
+		} else {
 			err = -EINVAL;
+			goto setup_exit;
+		}
 	}
 
 	pm_runtime_put(&sdd->pdev->dev);
+	disable_cs(sdd, spi);
+	return 0;
 
 setup_exit:
-
 	/* setup() returns with device de-selected */
 	disable_cs(sdd, spi);
 
+err_msgq:
+	gpio_free(cs->line);
+	spi_set_ctldata(spi, NULL);
+
+err_gpio_req:
+	kfree(cs);
+
 	return err;
 }
 
@@ -923,8 +988,11 @@  static void s3c64xx_spi_cleanup(struct spi_device *spi)
 {
 	struct s3c64xx_spi_csinfo *cs = spi_get_ctldata(spi);
 
-	if (cs)
+	if (cs) {
 		gpio_free(cs->line);
+		if (spi->dev.of_node)
+			kfree(cs);
+	}
 	spi_set_ctldata(spi, NULL);
 }
 
@@ -989,49 +1057,166 @@  static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
 	flush_fifo(sdd);
 }
 
+static int __devinit s3c64xx_spi_get_dmares(
+			struct s3c64xx_spi_driver_data *sdd, bool tx)
+{
+	struct platform_device *pdev = sdd->pdev;
+	struct s3c64xx_spi_dma_data *dma_data;
+	struct property *prop;
+	struct resource *res;
+	char prop_name[15], *chan_str;
+
+	if (tx) {
+		dma_data = &sdd->tx_dma;
+		dma_data->direction = DMA_TO_DEVICE;
+		chan_str = "tx";
+	} else {
+		dma_data = &sdd->rx_dma;
+		dma_data->direction = DMA_FROM_DEVICE;
+		chan_str = "rx";
+	}
+
+	if (!sdd->pdev->dev.of_node) {
+		res = platform_get_resource(pdev, IORESOURCE_DMA, tx ? 0 : 1);
+		if (!res) {
+			dev_err(&pdev->dev, "Unable to get SPI-%s dma "
+					"resource\n", chan_str);
+			return -ENXIO;
+		}
+		dma_data->dmach = res->start;
+		return 0;
+	}
+
+	sprintf(prop_name, "%s-dma-channel", chan_str);
+	prop = of_find_property(pdev->dev.of_node, prop_name, NULL);
+	if (!prop) {
+		dev_err(&pdev->dev, "%s dma channel property not specified\n",
+					chan_str);
+		return -ENXIO;
+	}
+
+	dma_data->dmach = DMACH_DT_PROP;
+	dma_data->dma_prop = prop;
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static int s3c64xx_spi_parse_dt_gpio(struct s3c64xx_spi_driver_data *sdd)
+{
+	struct device *dev = &sdd->pdev->dev;
+	int idx, gpio, ret;
+
+	/* find gpios for mosi, miso and clock lines */
+	for (idx = 0; idx < 3; idx++) {
+		gpio = of_get_gpio(dev->of_node, idx);
+		if (!gpio_is_valid(gpio)) {
+			dev_err(dev, "invalid gpio[%d]: %d\n", idx, gpio);
+			goto free_gpio;
+		}
+
+		ret = gpio_request(gpio, "spi-bus");
+		if (ret) {
+			dev_err(dev, "gpio [%d] request failed\n", gpio);
+			goto free_gpio;
+		}
+	}
+	return 0;
+
+free_gpio:
+	while (--idx >= 0)
+		gpio_free(sdd->gpios[idx]);
+	return -EINVAL;
+}
+
+static void s3c64xx_spi_dt_gpio_free(struct s3c64xx_spi_driver_data *sdd)
+{
+	unsigned int idx;
+	for (idx = 0; idx < 3; idx++)
+		gpio_free(sdd->gpios[idx]);
+}
+
+static struct __devinit s3c64xx_spi_info * s3c64xx_spi_parse_dt(
+						struct device *dev)
+{
+	struct s3c64xx_spi_info *sci;
+	u32 temp;
+
+	sci = devm_kzalloc(dev, sizeof(*sci), GFP_KERNEL);
+	if (!sci) {
+		dev_err(dev, "memory allocation for spi_info failed\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	if (of_property_read_u32(dev->of_node, "samsung,spi-src-clk", &temp)) {
+		dev_warn(dev, "spi bus clock parent not specified, using "
+				"clock at index 0 as parent\n");
+		sci->src_clk_nr = 0;
+	} else {
+		sci->src_clk_nr = temp;
+	}
+
+	if (of_property_read_u32(dev->of_node, "num-cs", &temp)) {
+		dev_warn(dev, "number of chip select lines not specified, "
+				"assuming 1 chip select line\n");
+		sci->num_cs = 1;
+	} else {
+		sci->num_cs = temp;
+	}
+
+	return sci;
+}
+#else
+static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
+{
+	return dev->platform_data;
+}
+
+static int s3c64xx_spi_parse_dt_gpio(struct s3c64xx_spi_driver_data *sdd)
+{
+	return -EINVAL;
+}
+
+static void s3c64xx_spi_dt_gpio_free(struct s3c64xx_spi_driver_data *sdd)
+{
+}
+#endif
+
+static const struct of_device_id s3c64xx_spi_dt_match[];
+
 static inline struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config(
 						struct platform_device *pdev)
 {
+#ifdef CONFIG_OF
+	if (pdev->dev.of_node) {
+		const struct of_device_id *match;
+		match = of_match_node(s3c64xx_spi_dt_match, pdev->dev.of_node);
+		return (struct s3c64xx_spi_port_config *)match->data;
+	}
+#endif
 	return (struct s3c64xx_spi_port_config *)
 			 platform_get_device_id(pdev)->driver_data;
 }
 
 static int __init s3c64xx_spi_probe(struct platform_device *pdev)
 {
-	struct resource	*mem_res, *dmatx_res, *dmarx_res;
+	struct resource	*mem_res;
 	struct s3c64xx_spi_driver_data *sdd;
-	struct s3c64xx_spi_info *sci;
+	struct s3c64xx_spi_info *sci = pdev->dev.platform_data;
 	struct spi_master *master;
 	int ret, irq;
 	char clk_name[16];
 
-	if (pdev->id < 0) {
-		dev_err(&pdev->dev,
-				"Invalid platform device id-%d\n", pdev->id);
-		return -ENODEV;
+	if (!sci && pdev->dev.of_node) {
+		sci = s3c64xx_spi_parse_dt(&pdev->dev);
+		if (IS_ERR(sci))
+			return PTR_ERR(sci);
 	}
 
-	if (pdev->dev.platform_data == NULL) {
+	if (!sci) {
 		dev_err(&pdev->dev, "platform_data missing!\n");
 		return -ENODEV;
 	}
 
-	sci = pdev->dev.platform_data;
-
-	/* Check for availability of necessary resource */
-
-	dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-	if (dmatx_res == NULL) {
-		dev_err(&pdev->dev, "Unable to get SPI-Tx dma resource\n");
-		return -ENXIO;
-	}
-
-	dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-	if (dmarx_res == NULL) {
-		dev_err(&pdev->dev, "Unable to get SPI-Rx dma resource\n");
-		return -ENXIO;
-	}
-
 	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (mem_res == NULL) {
 		dev_err(&pdev->dev, "Unable to get SPI MEM resource\n");
@@ -1059,14 +1244,29 @@  static int __init s3c64xx_spi_probe(struct platform_device *pdev)
 	sdd->cntrlr_info = sci;
 	sdd->pdev = pdev;
 	sdd->sfr_start = mem_res->start;
-	sdd->tx_dma.dmach = dmatx_res->start;
-	sdd->tx_dma.direction = DMA_MEM_TO_DEV;
-	sdd->rx_dma.dmach = dmarx_res->start;
-	sdd->rx_dma.direction = DMA_DEV_TO_MEM;
-	sdd->port_id = pdev->id;
-
+	if (pdev->dev.of_node) {
+		ret = of_alias_get_id(pdev->dev.of_node, "spi");
+		if (ret < 0) {
+			dev_err(&pdev->dev, "failed to get alias id, "
+						"errno %d\n", ret);
+			goto err0;
+		}
+		sdd->port_id = ret;
+	} else {
+		sdd->port_id = pdev->id;
+	}
+
 	sdd->cur_bpw = 8;
 
+	ret = s3c64xx_spi_get_dmares(sdd, true);
+	if (ret)
+		goto err0;
+
+	ret = s3c64xx_spi_get_dmares(sdd, false);
+	if (ret)
+		goto err0;
+
+	master->dev.of_node = pdev->dev.of_node;
 	master->bus_num = sdd->port_id;
 	master->setup = s3c64xx_spi_setup;
 	master->cleanup = s3c64xx_spi_cleanup;
@@ -1092,7 +1292,10 @@  static int __init s3c64xx_spi_probe(struct platform_device *pdev)
 		goto err1;
 	}
 
-	if (sci->cfg_gpio == NULL || sci->cfg_gpio()) {
+	if (!sci->cfg_gpio && pdev->dev.of_node) {
+		if (s3c64xx_spi_parse_dt_gpio(sdd))
+			return -EBUSY;
+	} else if (sci->cfg_gpio == NULL || sci->cfg_gpio()) {
 		dev_err(&pdev->dev, "Unable to config gpio\n");
 		ret = -EBUSY;
 		goto err2;
@@ -1173,6 +1376,8 @@  err5:
 err4:
 	clk_put(sdd->clk);
 err3:
+	if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node)
+		s3c64xx_spi_dt_gpio_free(sdd);
 err2:
 	iounmap((void *) sdd->regs);
 err1:
@@ -1204,6 +1409,9 @@  static int s3c64xx_spi_remove(struct platform_device *pdev)
 	clk_disable(sdd->clk);
 	clk_put(sdd->clk);
 
+	if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node)
+		s3c64xx_spi_dt_gpio_free(sdd);
+
 	iounmap((void *) sdd->regs);
 
 	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1228,6 +1436,9 @@  static int s3c64xx_spi_suspend(struct device *dev)
 	clk_disable(sdd->src_clk);
 	clk_disable(sdd->clk);
 
+	if (!sdd->cntrlr_info->cfg_gpio && dev->of_node)
+		s3c64xx_spi_dt_gpio_free(sdd);
+
 	sdd->cur_speed = 0; /* Output Clock is stopped */
 
 	return 0;
@@ -1239,7 +1450,10 @@  static int s3c64xx_spi_resume(struct device *dev)
 	struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
 	struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
 
-	sci->cfg_gpio();
+	if (!sci->cfg_gpio && dev->of_node)
+		s3c64xx_spi_parse_dt_gpio(sdd);
+	else
+		sci->cfg_gpio();
 
 	/* Enable the clock */
 	clk_enable(sdd->src_clk);
@@ -1347,11 +1561,22 @@  static struct platform_device_id s3c64xx_spi_driver_ids[] = {
 	{ },
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id s3c64xx_spi_dt_match[] = {
+	{ .compatible = "samsung,exynos4210-spi",
+			.data = (void *)&exynos4_spi_port_config,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match);
+#endif /* CONFIG_OF */
+
 static struct platform_driver s3c64xx_spi_driver = {
 	.driver = {
 		.name	= "s3c64xx-spi",
 		.owner = THIS_MODULE,
 		.pm = &s3c64xx_spi_pm,
+		.of_match_table = of_match_ptr(s3c64xx_spi_dt_match),
 	},
 	.remove = s3c64xx_spi_remove,
 	.id_table = s3c64xx_spi_driver_ids,