linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] ARM: mxs: Provide a common header file for SSP controller
@ 2012-04-19  0:30 Fabio Estevam
       [not found] ` <1334795434-8780-1-git-send-email-festevam-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 7+ messages in thread
From: Fabio Estevam @ 2012-04-19  0:30 UTC (permalink / raw)
  To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: Fabio Estevam, shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	snijsure-4jo+YWezP1RWk0Htik3J/w,
	marek.vasut-Re5JQEeQqe8AvxtiuMwx3w,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ, Chris Ball

On mxs SoCs the SSP controller can act as MMC or SPI controller.

Remove the SSP related definitions from the mxs-mmc driver and put it on a 
common header file.

This will facilitate the introduction of the spi-mxs driver.

Cc: Chris Ball <cjb-2X9k7bc8m7Mdnm+yROfE0A@public.gmane.org>
Signed-off-by: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
 arch/arm/mach-mxs/include/mach/ssp-regs.h |  114 +++++++++++++++++++++++++++++
 drivers/mmc/host/mxs-mmc.c                |   93 +-----------------------
 2 files changed, 116 insertions(+), 91 deletions(-)
 create mode 100644 arch/arm/mach-mxs/include/mach/ssp-regs.h

diff --git a/arch/arm/mach-mxs/include/mach/ssp-regs.h b/arch/arm/mach-mxs/include/mach/ssp-regs.h
new file mode 100644
index 0000000..4bb0b27
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/ssp-regs.h
@@ -0,0 +1,114 @@
+/*
+ * Freescale MXS SSP Registers
+ *
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SSP_REGS_H
+#define __SSP_REGS_H
+
+
+/* card detect polling timeout */
+#define MXS_MMC_DETECT_TIMEOUT			(HZ/2)
+
+#define SSP_VERSION_LATEST	4
+#define ssp_is_old()		(rev_struct < SSP_VERSION_LATEST)
+
+/* SSP registers */
+#define HW_SSP_CTRL0				0x000
+#define BM_SSP_CTRL0_RUN			(1 << 29)
+#define BM_SSP_CTRL0_SDIO_IRQ_CHECK		(1 << 28)
+#define BM_SSP_CTRL0_IGNORE_CRC			(1 << 26)
+#define BM_SSP_CTRL0_READ			(1 << 25)
+#define BM_SSP_CTRL0_DATA_XFER			(1 << 24)
+#define BP_SSP_CTRL0_BUS_WIDTH			22
+#define BM_SSP_CTRL0_BUS_WIDTH			(0x3 << 22)
+#define BM_SSP_CTRL0_WAIT_FOR_IRQ		(1 << 21)
+#define BM_SSP_CTRL0_LONG_RESP			(1 << 19)
+#define BM_SSP_CTRL0_GET_RESP			(1 << 17)
+#define BM_SSP_CTRL0_ENABLE			(1 << 16)
+#define BP_SSP_CTRL0_XFER_COUNT			0
+#define BM_SSP_CTRL0_XFER_COUNT			0xffff
+#define HW_SSP_CMD0				0x010
+#define BM_SSP_CMD0_DBL_DATA_RATE_EN		(1 << 25)
+#define BM_SSP_CMD0_SLOW_CLKING_EN		(1 << 22)
+#define BM_SSP_CMD0_CONT_CLKING_EN		(1 << 21)
+#define BM_SSP_CMD0_APPEND_8CYC			(1 << 20)
+#define BP_SSP_CMD0_BLOCK_SIZE			16
+#define BM_SSP_CMD0_BLOCK_SIZE			(0xf << 16)
+#define BP_SSP_CMD0_BLOCK_COUNT			8
+#define BM_SSP_CMD0_BLOCK_COUNT			(0xff << 8)
+#define BP_SSP_CMD0_CMD				0
+#define BM_SSP_CMD0_CMD				0xff
+#define HW_SSP_CMD1				0x020
+#define HW_SSP_XFER_SIZE			0x030
+#define HW_SSP_BLOCK_SIZE			0x040
+#define BP_SSP_BLOCK_SIZE_BLOCK_COUNT		4
+#define BM_SSP_BLOCK_SIZE_BLOCK_COUNT		(0xffffff << 4)
+#define BP_SSP_BLOCK_SIZE_BLOCK_SIZE		0
+#define BM_SSP_BLOCK_SIZE_BLOCK_SIZE		0xf
+#define HW_SSP_TIMING				(ssp_is_old() ? 0x050 : 0x070)
+#define BP_SSP_TIMING_TIMEOUT			16
+#define BM_SSP_TIMING_TIMEOUT			(0xffff << 16)
+#define BP_SSP_TIMING_CLOCK_DIVIDE		8
+#define BM_SSP_TIMING_CLOCK_DIVIDE		(0xff << 8)
+#define BP_SSP_TIMING_CLOCK_RATE		0
+#define BM_SSP_TIMING_CLOCK_RATE		0xff
+#define HW_SSP_CTRL1				(ssp_is_old() ? 0x060 : 0x080)
+#define BM_SSP_CTRL1_SDIO_IRQ			(1 << 31)
+#define BM_SSP_CTRL1_SDIO_IRQ_EN		(1 << 30)
+#define BM_SSP_CTRL1_RESP_ERR_IRQ		(1 << 29)
+#define BM_SSP_CTRL1_RESP_ERR_IRQ_EN		(1 << 28)
+#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ		(1 << 27)
+#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN	(1 << 26)
+#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ		(1 << 25)
+#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN	(1 << 24)
+#define BM_SSP_CTRL1_DATA_CRC_IRQ		(1 << 23)
+#define BM_SSP_CTRL1_DATA_CRC_IRQ_EN		(1 << 22)
+#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ		(1 << 21)
+#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ_EN	(1 << 20)
+#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ		(1 << 17)
+#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN	(1 << 16)
+#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ		(1 << 15)
+#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN	(1 << 14)
+#define BM_SSP_CTRL1_DMA_ENABLE			(1 << 13)
+#define BM_SSP_CTRL1_POLARITY			(1 << 9)
+#define BP_SSP_CTRL1_WORD_LENGTH		4
+#define BM_SSP_CTRL1_WORD_LENGTH		(0xf << 4)
+#define BP_SSP_CTRL1_SSP_MODE			0
+#define BM_SSP_CTRL1_SSP_MODE			0xf
+#define HW_SSP_SDRESP0				(ssp_is_old() ? 0x080 : 0x0a0)
+#define HW_SSP_SDRESP1				(ssp_is_old() ? 0x090 : 0x0b0)
+#define HW_SSP_SDRESP2				(ssp_is_old() ? 0x0a0 : 0x0c0)
+#define HW_SSP_SDRESP3				(ssp_is_old() ? 0x0b0 : 0x0d0)
+#define HW_SSP_STATUS				(ssp_is_old() ? 0x0c0 : 0x100)
+#define BM_SSP_STATUS_CARD_DETECT		(1 << 28)
+#define BM_SSP_STATUS_SDIO_IRQ			(1 << 17)
+#define HW_SSP_VERSION				(cpu_is_mx23() ? 0x110 : 0x130)
+#define BP_SSP_VERSION_MAJOR			24
+
+#define BF_SSP(value, field)	(((value) << BP_SSP_##field) & BM_SSP_##field)
+
+#define MXS_MMC_IRQ_BITS	(BM_SSP_CTRL1_SDIO_IRQ		| \
+				 BM_SSP_CTRL1_RESP_ERR_IRQ	| \
+				 BM_SSP_CTRL1_RESP_TIMEOUT_IRQ	| \
+				 BM_SSP_CTRL1_DATA_TIMEOUT_IRQ	| \
+				 BM_SSP_CTRL1_DATA_CRC_IRQ	| \
+				 BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ	| \
+				 BM_SSP_CTRL1_RECV_TIMEOUT_IRQ  | \
+				 BM_SSP_CTRL1_FIFO_OVERRUN_IRQ)
+
+#define SSP_PIO_NUM	3
+
+#endif /* __SSP_REGS_H */
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index b0f2ef9..44d19ef 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -43,100 +43,11 @@
 #include <mach/mxs.h>
 #include <mach/common.h>
 #include <mach/mmc.h>
+#include <mach/ssp-regs.h>
 
 #define DRIVER_NAME	"mxs-mmc"
 
-/* card detect polling timeout */
-#define MXS_MMC_DETECT_TIMEOUT			(HZ/2)
-
-#define SSP_VERSION_LATEST	4
-#define ssp_is_old()		(host->version < SSP_VERSION_LATEST)
-
-/* SSP registers */
-#define HW_SSP_CTRL0				0x000
-#define  BM_SSP_CTRL0_RUN			(1 << 29)
-#define  BM_SSP_CTRL0_SDIO_IRQ_CHECK		(1 << 28)
-#define  BM_SSP_CTRL0_IGNORE_CRC		(1 << 26)
-#define  BM_SSP_CTRL0_READ			(1 << 25)
-#define  BM_SSP_CTRL0_DATA_XFER			(1 << 24)
-#define  BP_SSP_CTRL0_BUS_WIDTH			(22)
-#define  BM_SSP_CTRL0_BUS_WIDTH			(0x3 << 22)
-#define  BM_SSP_CTRL0_WAIT_FOR_IRQ		(1 << 21)
-#define  BM_SSP_CTRL0_LONG_RESP			(1 << 19)
-#define  BM_SSP_CTRL0_GET_RESP			(1 << 17)
-#define  BM_SSP_CTRL0_ENABLE			(1 << 16)
-#define  BP_SSP_CTRL0_XFER_COUNT		(0)
-#define  BM_SSP_CTRL0_XFER_COUNT		(0xffff)
-#define HW_SSP_CMD0				0x010
-#define  BM_SSP_CMD0_DBL_DATA_RATE_EN		(1 << 25)
-#define  BM_SSP_CMD0_SLOW_CLKING_EN		(1 << 22)
-#define  BM_SSP_CMD0_CONT_CLKING_EN		(1 << 21)
-#define  BM_SSP_CMD0_APPEND_8CYC		(1 << 20)
-#define  BP_SSP_CMD0_BLOCK_SIZE			(16)
-#define  BM_SSP_CMD0_BLOCK_SIZE			(0xf << 16)
-#define  BP_SSP_CMD0_BLOCK_COUNT		(8)
-#define  BM_SSP_CMD0_BLOCK_COUNT		(0xff << 8)
-#define  BP_SSP_CMD0_CMD			(0)
-#define  BM_SSP_CMD0_CMD			(0xff)
-#define HW_SSP_CMD1				0x020
-#define HW_SSP_XFER_SIZE			0x030
-#define HW_SSP_BLOCK_SIZE			0x040
-#define  BP_SSP_BLOCK_SIZE_BLOCK_COUNT		(4)
-#define  BM_SSP_BLOCK_SIZE_BLOCK_COUNT		(0xffffff << 4)
-#define  BP_SSP_BLOCK_SIZE_BLOCK_SIZE		(0)
-#define  BM_SSP_BLOCK_SIZE_BLOCK_SIZE		(0xf)
-#define HW_SSP_TIMING				(ssp_is_old() ? 0x050 : 0x070)
-#define  BP_SSP_TIMING_TIMEOUT			(16)
-#define  BM_SSP_TIMING_TIMEOUT			(0xffff << 16)
-#define  BP_SSP_TIMING_CLOCK_DIVIDE		(8)
-#define  BM_SSP_TIMING_CLOCK_DIVIDE		(0xff << 8)
-#define  BP_SSP_TIMING_CLOCK_RATE		(0)
-#define  BM_SSP_TIMING_CLOCK_RATE		(0xff)
-#define HW_SSP_CTRL1				(ssp_is_old() ? 0x060 : 0x080)
-#define  BM_SSP_CTRL1_SDIO_IRQ			(1 << 31)
-#define  BM_SSP_CTRL1_SDIO_IRQ_EN		(1 << 30)
-#define  BM_SSP_CTRL1_RESP_ERR_IRQ		(1 << 29)
-#define  BM_SSP_CTRL1_RESP_ERR_IRQ_EN		(1 << 28)
-#define  BM_SSP_CTRL1_RESP_TIMEOUT_IRQ		(1 << 27)
-#define  BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN	(1 << 26)
-#define  BM_SSP_CTRL1_DATA_TIMEOUT_IRQ		(1 << 25)
-#define  BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN	(1 << 24)
-#define  BM_SSP_CTRL1_DATA_CRC_IRQ		(1 << 23)
-#define  BM_SSP_CTRL1_DATA_CRC_IRQ_EN		(1 << 22)
-#define  BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ		(1 << 21)
-#define  BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ_EN	(1 << 20)
-#define  BM_SSP_CTRL1_RECV_TIMEOUT_IRQ		(1 << 17)
-#define  BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN	(1 << 16)
-#define  BM_SSP_CTRL1_FIFO_OVERRUN_IRQ		(1 << 15)
-#define  BM_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN	(1 << 14)
-#define  BM_SSP_CTRL1_DMA_ENABLE		(1 << 13)
-#define  BM_SSP_CTRL1_POLARITY			(1 << 9)
-#define  BP_SSP_CTRL1_WORD_LENGTH		(4)
-#define  BM_SSP_CTRL1_WORD_LENGTH		(0xf << 4)
-#define  BP_SSP_CTRL1_SSP_MODE			(0)
-#define  BM_SSP_CTRL1_SSP_MODE			(0xf)
-#define HW_SSP_SDRESP0				(ssp_is_old() ? 0x080 : 0x0a0)
-#define HW_SSP_SDRESP1				(ssp_is_old() ? 0x090 : 0x0b0)
-#define HW_SSP_SDRESP2				(ssp_is_old() ? 0x0a0 : 0x0c0)
-#define HW_SSP_SDRESP3				(ssp_is_old() ? 0x0b0 : 0x0d0)
-#define HW_SSP_STATUS				(ssp_is_old() ? 0x0c0 : 0x100)
-#define  BM_SSP_STATUS_CARD_DETECT		(1 << 28)
-#define  BM_SSP_STATUS_SDIO_IRQ			(1 << 17)
-#define HW_SSP_VERSION				(cpu_is_mx23() ? 0x110 : 0x130)
-#define  BP_SSP_VERSION_MAJOR			(24)
-
-#define BF_SSP(value, field)	(((value) << BP_SSP_##field) & BM_SSP_##field)
-
-#define MXS_MMC_IRQ_BITS	(BM_SSP_CTRL1_SDIO_IRQ		| \
-				 BM_SSP_CTRL1_RESP_ERR_IRQ	| \
-				 BM_SSP_CTRL1_RESP_TIMEOUT_IRQ	| \
-				 BM_SSP_CTRL1_DATA_TIMEOUT_IRQ	| \
-				 BM_SSP_CTRL1_DATA_CRC_IRQ	| \
-				 BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ	| \
-				 BM_SSP_CTRL1_RECV_TIMEOUT_IRQ  | \
-				 BM_SSP_CTRL1_FIFO_OVERRUN_IRQ)
-
-#define SSP_PIO_NUM	3
+#define rev_struct	(host->version)
 
 struct mxs_mmc_host {
 	struct mmc_host			*mmc;
-- 
1.7.1


------------------------------------------------------------------------------
For Developers, A Lot Can Happen In A Second.
Boundary is the first to Know...and Tell You.
Monitor Your Applications in Ultra-Fine Resolution. Try it FREE!
http://p.sf.net/sfu/Boundary-d2dvs2

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] spi: Add initial support for spi-mxs
       [not found] ` <1334795434-8780-1-git-send-email-festevam-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2012-04-19  0:30   ` Fabio Estevam
       [not found]     ` <1334795434-8780-2-git-send-email-festevam-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2012-04-20  2:59   ` [PATCH 1/2] ARM: mxs: Provide a common header file for SSP controller Shawn Guo
  1 sibling, 1 reply; 7+ messages in thread
From: Fabio Estevam @ 2012-04-19  0:30 UTC (permalink / raw)
  To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: Fabio Estevam, snijsure-4jo+YWezP1RWk0Htik3J/w,
	marek.vasut-Re5JQEeQqe8AvxtiuMwx3w,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ, shawn.guo-QSEj5FYQhm4dnm+yROfE0A

Add initial support for the spi driver on mxs processors.

Currently only PIO mode is supported.

Tested with a sst25vf016b spi flash on a mx28evk board using mtd-utils.

Signed-off-by: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
It still does not contain DT support, but I wanted to post it as is, so
that people can test it and I would also like to get some initial feedback.

 arch/arm/mach-mxs/include/mach/ssp-regs.h |   32 ++
 drivers/spi/Kconfig                       |    6 +
 drivers/spi/Makefile                      |    1 +
 drivers/spi/spi-mxs.c                     |  457 +++++++++++++++++++++++++++++
 4 files changed, 496 insertions(+), 0 deletions(-)
 create mode 100644 drivers/spi/spi-mxs.c

diff --git a/arch/arm/mach-mxs/include/mach/ssp-regs.h b/arch/arm/mach-mxs/include/mach/ssp-regs.h
index 4bb0b27..fc467fa 100644
--- a/arch/arm/mach-mxs/include/mach/ssp-regs.h
+++ b/arch/arm/mach-mxs/include/mach/ssp-regs.h
@@ -27,6 +27,10 @@
 
 /* SSP registers */
 #define HW_SSP_CTRL0				0x000
+#define HW_SSP_CTRL0_SET			0x00000004
+#define HW_SSP_CTRL0_CLR			0x00000008
+#define HW_SSP_CTRL0_TOG			0x0000000c
+#define BM_SSP_CTRL0_LOCK_CS			0x08000000
 #define BM_SSP_CTRL0_RUN			(1 << 29)
 #define BM_SSP_CTRL0_SDIO_IRQ_CHECK		(1 << 28)
 #define BM_SSP_CTRL0_IGNORE_CRC			(1 << 26)
@@ -41,6 +45,10 @@
 #define BP_SSP_CTRL0_XFER_COUNT			0
 #define BM_SSP_CTRL0_XFER_COUNT			0xffff
 #define HW_SSP_CMD0				0x010
+#define HW_SSP_CMD0_SET				0x014
+#define HW_SSP_CMD0_CLR				0x018
+#define HW_SSP_CMD0_TOG				0x01c
+
 #define BM_SSP_CMD0_DBL_DATA_RATE_EN		(1 << 25)
 #define BM_SSP_CMD0_SLOW_CLKING_EN		(1 << 22)
 #define BM_SSP_CMD0_CONT_CLKING_EN		(1 << 21)
@@ -63,8 +71,12 @@
 #define BM_SSP_TIMING_TIMEOUT			(0xffff << 16)
 #define BP_SSP_TIMING_CLOCK_DIVIDE		8
 #define BM_SSP_TIMING_CLOCK_DIVIDE		(0xff << 8)
+#define BF_SSP_TIMING_CLOCK_DIVIDE(v)  \
+		(((v) << 8) & BM_SSP_TIMING_CLOCK_DIVIDE)
 #define BP_SSP_TIMING_CLOCK_RATE		0
 #define BM_SSP_TIMING_CLOCK_RATE		0xff
+#define BF_SSP_TIMING_CLOCK_RATE(v)  \
+		(((v) << 0) & BM_SSP_TIMING_CLOCK_RATE)
 #define HW_SSP_CTRL1				(ssp_is_old() ? 0x060 : 0x080)
 #define BM_SSP_CTRL1_SDIO_IRQ			(1 << 31)
 #define BM_SSP_CTRL1_SDIO_IRQ_EN		(1 << 30)
@@ -83,11 +95,30 @@
 #define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ		(1 << 15)
 #define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN	(1 << 14)
 #define BM_SSP_CTRL1_DMA_ENABLE			(1 << 13)
+#define BM_SSP_CTRL1_PHASE			0x00000400
 #define BM_SSP_CTRL1_POLARITY			(1 << 9)
 #define BP_SSP_CTRL1_WORD_LENGTH		4
 #define BM_SSP_CTRL1_WORD_LENGTH		(0xf << 4)
+#define BF_SSP_CTRL1_WORD_LENGTH(v)  \
+		(((v) << 4) & BM_SSP_CTRL1_WORD_LENGTH)
+#define BV_SSP_CTRL1_WORD_LENGTH__RESERVED0	0x0
+#define BV_SSP_CTRL1_WORD_LENGTH__RESERVED1	0x1
+#define BV_SSP_CTRL1_WORD_LENGTH__RESERVED2	0x2
+#define BV_SSP_CTRL1_WORD_LENGTH__FOUR_BITS	0x3
+#define BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS	0x7
+#define BV_SSP_CTRL1_WORD_LENGTH__SIXTEEN_BITS	0xF
+#define BM_SSP_CTRL0_WAIT_FOR_CMD		0x00100000
 #define BP_SSP_CTRL1_SSP_MODE			0
 #define BM_SSP_CTRL1_SSP_MODE			0xf
+#define BF_SSP_CTRL1_SSP_MODE(v)  \
+		(((v) << 0) & BM_SSP_CTRL1_SSP_MODE)
+#define BV_SSP_CTRL1_SSP_MODE__SPI		0x0
+#define BV_SSP_CTRL1_SSP_MODE__SSI		0x1
+#define BV_SSP_CTRL1_SSP_MODE__SD_MMC		0x3
+#define BV_SSP_CTRL1_SSP_MODE__MS		0x4
+
+#define HW_SSP_DATA				0x090
+
 #define HW_SSP_SDRESP0				(ssp_is_old() ? 0x080 : 0x0a0)
 #define HW_SSP_SDRESP1				(ssp_is_old() ? 0x090 : 0x0b0)
 #define HW_SSP_SDRESP2				(ssp_is_old() ? 0x0a0 : 0x0c0)
@@ -95,6 +126,7 @@
 #define HW_SSP_STATUS				(ssp_is_old() ? 0x0c0 : 0x100)
 #define BM_SSP_STATUS_CARD_DETECT		(1 << 28)
 #define BM_SSP_STATUS_SDIO_IRQ			(1 << 17)
+#define BM_SSP_STATUS_FIFO_EMPTY		0x00000020
 #define HW_SSP_VERSION				(cpu_is_mx23() ? 0x110 : 0x130)
 #define BP_SSP_VERSION_MAJOR			24
 
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 3ed7483..f951604 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -199,6 +199,12 @@ config SPI_MPC512x_PSC
 	  This enables using the Freescale MPC5121 Programmable Serial
 	  Controller in SPI master mode.
 
+config SPI_MXS
+	tristate "Freescale MXS SPI controller"
+	depends on ARCH_MXS
+	help
+	   SPI driver for Freescale MXS devices
+
 config SPI_FSL_LIB
 	tristate
 	depends on FSL_SOC
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index a1d48e0..0e6fe03 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_SPI_LM70_LLP)		+= spi-lm70llp.o
 obj-$(CONFIG_SPI_MPC512x_PSC)		+= spi-mpc512x-psc.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)		+= spi-mpc52xx-psc.o
 obj-$(CONFIG_SPI_MPC52xx)		+= spi-mpc52xx.o
+obj-$(CONFIG_SPI_MXS)			+= spi-mxs.o
 obj-$(CONFIG_SPI_NUC900)		+= spi-nuc900.o
 obj-$(CONFIG_SPI_OC_TINY)		+= spi-oc-tiny.o
 obj-$(CONFIG_SPI_OMAP_UWIRE)		+= spi-omap-uwire.o
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
new file mode 100644
index 0000000..3550ab6
--- /dev/null
+++ b/drivers/spi/spi-mxs.c
@@ -0,0 +1,457 @@
+/*
+ * Freescale MXS SPI master driver
+ *
+ * Heavily based on spi-stmp.c, which is:
+ * Author: dmitry pervushin <dimka-L1vi/lXTdtvkgf6YlCu6wwC/G2K4zDHf@public.gmane.org>
+ *
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <mach/mxs.h>
+#include <mach/ssp-regs.h>
+#include <mach/common.h>
+
+#define SSP_TIMEOUT		200	/* 200 ms */
+
+#define rev_struct		(ss->version)
+
+struct mxs_spi {
+	void __iomem *regs;	/* vaddr of the control registers */
+
+	u32 speed_khz;
+	u32 divider;
+
+	struct clk *clk;
+	struct device *master_dev;
+
+	struct work_struct work;
+	struct workqueue_struct *workqueue;
+	spinlock_t lock;
+	struct list_head queue;
+
+	u32 version;
+};
+
+static int mxs_spi_setup_transfer(struct spi_device *spi,
+				  struct spi_transfer *t)
+{
+	u8 bits_per_word;
+	u32 hz;
+	struct mxs_spi *ss;
+	u16 rate;
+
+	ss = spi_master_get_devdata(spi->master);
+
+	bits_per_word = spi->bits_per_word;
+	if (t && t->bits_per_word)
+		bits_per_word = t->bits_per_word;
+/*
+ * Calculate speed:
+ * - by default, use maximum speed from ssp clk
+ * - if device overrides it, use it
+ * - if transfer specifies other speed, use transfer's one
+ */
+	hz = 1000 * ss->speed_khz / ss->divider;
+	if (spi->max_speed_hz)
+		hz = min(hz, spi->max_speed_hz);
+	if (t && t->speed_hz)
+		hz = min(hz, t->speed_hz);
+
+	if (hz == 0) {
+		dev_err(&spi->dev, "Cannot continue with zero clock\n");
+		return -EINVAL;
+	}
+
+	if (bits_per_word != 8) {
+		dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
+			__func__, bits_per_word);
+		return -EINVAL;
+	}
+
+	dev_dbg(&spi->dev, "Requested clk rate = %uHz, max = %ukHz/%d = %uHz\n",
+		hz, ss->speed_khz, ss->divider,
+		ss->speed_khz * 1000 / ss->divider);
+
+	if (ss->speed_khz * 1000 / ss->divider < hz) {
+		dev_err(&spi->dev, "%s, unsupported clock rate %uHz\n",
+			__func__, hz);
+		return -EINVAL;
+	}
+
+	rate = 1000 * ss->speed_khz / ss->divider / hz;
+
+	__raw_writel(BF_SSP_TIMING_CLOCK_DIVIDE(ss->divider) |
+		     BF_SSP_TIMING_CLOCK_RATE(rate - 1),
+		     ss->regs + HW_SSP_TIMING);
+
+	__raw_writel(BF_SSP_CTRL1_SSP_MODE(BV_SSP_CTRL1_SSP_MODE__SPI) |
+		     BF_SSP_CTRL1_WORD_LENGTH
+		     (BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) |
+		     ((spi->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) |
+		     ((spi->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0),
+		     ss->regs + HW_SSP_CTRL1);
+
+	__raw_writel(0x0, ss->regs + HW_SSP_CMD0_SET);
+
+	return 0;
+}
+
+static void mxs_spi_cleanup(struct spi_device *spi)
+{
+	return;
+}
+
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA)
+static int mxs_spi_setup(struct spi_device *spi)
+{
+	struct mxs_spi *ss;
+	int err = 0;
+
+	ss = spi_master_get_devdata(spi->master);
+
+	if (!spi->bits_per_word)
+		spi->bits_per_word = 8;
+
+	if (spi->mode & ~MODEBITS)
+		return -EINVAL;
+
+	err = mxs_spi_setup_transfer(spi, NULL);
+	if (err)
+		dev_err(&spi->dev, "Failed to setup transfer: %d\n", err);
+
+	return err;
+}
+
+static inline u32 mxs_spi_cs(unsigned cs)
+{
+	return ((cs & 1) ? BM_SSP_CTRL0_WAIT_FOR_CMD : 0) |
+	    ((cs & 2) ? BM_SSP_CTRL0_WAIT_FOR_IRQ : 0);
+}
+
+static inline void mxs_spi_enable(struct mxs_spi *ss)
+{
+	__raw_writel(BM_SSP_CTRL0_LOCK_CS, ss->regs + HW_SSP_CTRL0_SET);
+	__raw_writel(BM_SSP_CTRL0_IGNORE_CRC, ss->regs + HW_SSP_CTRL0_CLR);
+}
+
+static inline void mxs_spi_disable(struct mxs_spi *ss)
+{
+	__raw_writel(BM_SSP_CTRL0_LOCK_CS, ss->regs + HW_SSP_CTRL0_CLR);
+	__raw_writel(BM_SSP_CTRL0_IGNORE_CRC, ss->regs + HW_SSP_CTRL0_SET);
+}
+
+int mxs_ssp_wait_set(struct mxs_spi *ss, int offset, int mask)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(SSP_TIMEOUT);
+
+	while (!(readl_relaxed(&ss->regs + offset) & mask)) {
+		udelay(1);
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+int mxs_ssp_wait_clr(struct mxs_spi *ss, int offset, int mask)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(SSP_TIMEOUT);
+
+	while ((readl_relaxed(&ss->regs + offset) & mask)) {
+		udelay(1);
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+static int mxs_spi_txrx_pio(struct mxs_spi *ss, int cs,
+			    unsigned char *buf, int len,
+			    int *first, int *last, int write)
+{
+	if (*first) {
+		mxs_spi_enable(ss);
+		*first = 0;
+	}
+
+	__raw_writel(mxs_spi_cs(cs), ss->regs + HW_SSP_CTRL0_SET);
+
+	while (len--) {
+		if (*last && len == 0) {
+			mxs_spi_disable(ss);
+			*last = 0;
+		}
+
+		if (ss->version > 3) {
+			__raw_writel(1, ss->regs + HW_SSP_XFER_SIZE);
+		} else {
+			__raw_writel(BM_SSP_CTRL0_XFER_COUNT,
+				     ss->regs + HW_SSP_CTRL0_CLR);
+			__raw_writel(1, ss->regs + HW_SSP_CTRL0_SET);
+		}
+
+		if (write)
+			__raw_writel(BM_SSP_CTRL0_READ,
+				     ss->regs + HW_SSP_CTRL0_CLR);
+		else
+			__raw_writel(BM_SSP_CTRL0_READ,
+				     ss->regs + HW_SSP_CTRL0_SET);
+
+		 /* Activate Run bit */
+		__raw_writel(BM_SSP_CTRL0_RUN, ss->regs + HW_SSP_CTRL0_SET);
+
+
+		if (mxs_ssp_wait_set(ss->regs, HW_SSP_CTRL0, BM_SSP_CTRL0_RUN))
+			return -ETIMEDOUT;
+
+		if (write)
+			__raw_writel(*buf, ss->regs + HW_SSP_DATA);
+
+		/* Set TRANSFER */
+		__raw_writel(BM_SSP_CTRL0_DATA_XFER,
+			     ss->regs + HW_SSP_CTRL0_SET);
+
+		if (!write) {
+			if (mxs_ssp_wait_clr(ss->regs, HW_SSP_STATUS,
+						BM_SSP_STATUS_FIFO_EMPTY))
+				return -ETIMEDOUT;
+
+			*buf = (__raw_readl(ss->regs + HW_SSP_DATA) & 0xFF);
+		}
+
+		if (mxs_ssp_wait_clr(ss->regs, HW_SSP_CTRL0, BM_SSP_CTRL0_RUN))
+			return -ETIMEDOUT;
+		/* advance to the next byte */
+		buf++;
+	}
+	return len < 0 ? 0 : -ETIMEDOUT;
+}
+
+static int mxs_spi_handle_message(struct mxs_spi *ss, struct spi_message *m)
+{
+	int first, last;
+	struct spi_transfer *t, *tmp_t;
+	int status = 0;
+	int cs;
+
+	first = last = 0;
+
+	cs = m->spi->chip_select;
+
+	list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) {
+
+		mxs_spi_setup_transfer(m->spi, t);
+
+		if (&t->transfer_list == m->transfers.next)
+			first = !0;
+		if (&t->transfer_list == m->transfers.prev)
+			last = !0;
+		if (t->rx_buf && t->tx_buf) {
+			pr_debug("%s: cannot send and receive simultaneously\n",
+				 __func__);
+			return -EINVAL;
+		}
+		/*
+		 *  REVISIT:
+		 *  here driver completely ignores setting of t->cs_change
+		 */
+		if (t->tx_buf)
+			status = mxs_spi_txrx_pio(ss, cs, (void *)t->tx_buf,
+					     t->len, &first, &last, 1);
+		if (t->rx_buf)
+			status = mxs_spi_txrx_pio(ss, cs, t->rx_buf,
+					     t->len, &first, &last, 0);
+		m->actual_length += t->len;
+		if (status)
+			break;
+
+		first = last = 0;
+	}
+	return status;
+}
+
+/*
+ * mxs_spi_handle
+ *
+ * The workhorse of the driver - it handles messages from the list
+ */
+static void mxs_spi_handle(struct work_struct *w)
+{
+	struct mxs_spi *ss = container_of(w, struct mxs_spi, work);
+	unsigned long flags;
+	struct spi_message *m;
+
+	BUG_ON(w == NULL);
+
+	spin_lock_irqsave(&ss->lock, flags);
+	while (!list_empty(&ss->queue)) {
+		m = list_entry(ss->queue.next, struct spi_message, queue);
+		list_del_init(&m->queue);
+		spin_unlock_irqrestore(&ss->lock, flags);
+
+		m->status = mxs_spi_handle_message(ss, m);
+		if (m->complete)
+			m->complete(m->context);
+
+		spin_lock_irqsave(&ss->lock, flags);
+	}
+	spin_unlock_irqrestore(&ss->lock, flags);
+
+	return;
+}
+
+/*
+ * mxs_spi_transfer
+ *
+ * Called indirectly from spi_async, queues all the messages to
+ * spi_handle_message
+ *
+ */
+static int mxs_spi_transfer(struct spi_device *spi, struct spi_message *m)
+{
+	struct mxs_spi *ss = spi_master_get_devdata(spi->master);
+	unsigned long flags;
+
+	m->actual_length = 0;
+	m->status = -EINPROGRESS;
+	spin_lock_irqsave(&ss->lock, flags);
+	list_add_tail(&m->queue, &ss->queue);
+	queue_work(ss->workqueue, &ss->work);
+	spin_unlock_irqrestore(&ss->lock, flags);
+
+	return 0;
+}
+
+static int __devinit mxs_spi_probe(struct platform_device *dev)
+{
+	int ret;
+	struct spi_master *master;
+	struct mxs_spi *ss;
+	struct resource *res;
+
+	master = spi_alloc_master(&dev->dev, sizeof(struct mxs_spi));
+	ss = spi_master_get_devdata(master);
+	ss->master_dev = &dev->dev;
+
+	if (!master)
+		return -ENOMEM;
+
+	platform_set_drvdata(dev, master);
+
+	INIT_WORK(&ss->work, mxs_spi_handle);
+	INIT_LIST_HEAD(&ss->queue);
+	spin_lock_init(&ss->lock);
+	ss->workqueue = create_singlethread_workqueue(dev_name(&dev->dev));
+	master->transfer = mxs_spi_transfer;
+	master->setup = mxs_spi_setup;
+	master->cleanup = mxs_spi_cleanup;
+	master->mode_bits = MODEBITS;
+
+	master->bus_num = dev->id;
+	master->num_chipselect = 1;
+
+	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENOENT;
+
+	ss->regs = devm_request_and_ioremap(&dev->dev, res);
+	if (!ss->regs)
+		return -EBUSY;
+
+	mxs_reset_block(ss->regs);
+	ss->clk = clk_get(&dev->dev, NULL);
+	if (IS_ERR(ss->clk)) {
+		ret = PTR_ERR(ss->clk);
+		dev_err(&dev->dev, "cannot get spi clk\n");
+		goto out_put_master;
+	}
+
+	clk_prepare_enable(ss->clk);
+
+	ss->speed_khz = clk_get_rate(ss->clk) / 1000;
+	ss->divider = 2;
+	dev_dbg(&dev->dev, "Max possible speed %d = %ld/%d kHz\n",
+		 ss->speed_khz, clk_get_rate(ss->clk), ss->divider);
+
+	ss->version = __raw_readl(ss->regs + HW_SSP_VERSION) >> 24;
+
+	ret = spi_register_master(master);
+	if (ret) {
+		dev_err(&dev->dev, "cannot register spi master, %d\n", ret);
+		goto out_clk_put;
+	}
+
+	dev_info(&dev->dev, "driver probed\n");
+
+	return 0;
+
+out_clk_put:
+	clk_disable_unprepare(ss->clk);
+	clk_put(ss->clk);
+out_put_master:
+	spi_master_put(master);
+	if (ss->workqueue)
+		destroy_workqueue(ss->workqueue);
+	platform_set_drvdata(dev, NULL);
+
+	return ret;
+}
+
+static int __devexit mxs_spi_remove(struct platform_device *dev)
+{
+	struct mxs_spi *ss;
+	struct spi_master *master;
+
+	master = platform_get_drvdata(dev);
+	if (!master)
+		goto out0;
+	ss = spi_master_get_devdata(master);
+
+	clk_disable_unprepare(ss->clk);
+	clk_put(ss->clk);
+	spi_unregister_master(master);
+
+	destroy_workqueue(ss->workqueue);
+	spi_master_put(master);
+	platform_set_drvdata(dev, NULL);
+out0:
+	return 0;
+}
+
+static struct platform_driver mxs_spi_driver = {
+	.probe = mxs_spi_probe,
+	.remove = __devexit_p(mxs_spi_remove),
+	.driver = {
+		   .name = "mxs-spi",
+		   .owner = THIS_MODULE,
+		   },
+};
+module_platform_driver(mxs_spi_driver);
+
+MODULE_AUTHOR("dmitry pervushin <dimka-L1vi/lXTdtvkgf6YlCu6wwC/G2K4zDHf@public.gmane.org>");
+MODULE_AUTHOR("Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org");
+MODULE_DESCRIPTION("MXS SPI master driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mxs-spi");
-- 
1.7.1


------------------------------------------------------------------------------
For Developers, A Lot Can Happen In A Second.
Boundary is the first to Know...and Tell You.
Monitor Your Applications in Ultra-Fine Resolution. Try it FREE!
http://p.sf.net/sfu/Boundary-d2dvs2

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] ARM: mxs: Provide a common header file for SSP controller
       [not found] ` <1334795434-8780-1-git-send-email-festevam-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2012-04-19  0:30   ` [PATCH 2/2] spi: Add initial support for spi-mxs Fabio Estevam
@ 2012-04-20  2:59   ` Shawn Guo
       [not found]     ` <20120420025918.GI22219-rvtDTF3kK1ictlrPMvKcciBecyulp+rMXqFh9Ls21Oc@public.gmane.org>
  1 sibling, 1 reply; 7+ messages in thread
From: Shawn Guo @ 2012-04-20  2:59 UTC (permalink / raw)
  To: Fabio Estevam
  Cc: Fabio Estevam, snijsure-4jo+YWezP1RWk0Htik3J/w,
	marek.vasut-Re5JQEeQqe8AvxtiuMwx3w,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Chris Ball

On Wed, Apr 18, 2012 at 09:30:33PM -0300, Fabio Estevam wrote:
> On mxs SoCs the SSP controller can act as MMC or SPI controller.
> 
> Remove the SSP related definitions from the mxs-mmc driver and put it on a 
> common header file.
> 
> This will facilitate the introduction of the spi-mxs driver.
> 
We are trying to remove <mach/*.h> from drivers.  And this patch moves
to the opposite direction.

Regards,
Shawn

> Cc: Chris Ball <cjb-2X9k7bc8m7Mdnm+yROfE0A@public.gmane.org>
> Signed-off-by: Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
> ---
>  arch/arm/mach-mxs/include/mach/ssp-regs.h |  114 +++++++++++++++++++++++++++++
>  drivers/mmc/host/mxs-mmc.c                |   93 +-----------------------
>  2 files changed, 116 insertions(+), 91 deletions(-)
>  create mode 100644 arch/arm/mach-mxs/include/mach/ssp-regs.h

------------------------------------------------------------------------------
For Developers, A Lot Can Happen In A Second.
Boundary is the first to Know...and Tell You.
Monitor Your Applications in Ultra-Fine Resolution. Try it FREE!
http://p.sf.net/sfu/Boundary-d2dvs2

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] ARM: mxs: Provide a common header file for SSP controller
       [not found]     ` <20120420025918.GI22219-rvtDTF3kK1ictlrPMvKcciBecyulp+rMXqFh9Ls21Oc@public.gmane.org>
@ 2012-04-20  3:07       ` Fabio Estevam
       [not found]         ` <CAOMZO5AOmAA93LLQnzHrOf+prH5rmNw7C-ZSpYzpKGUrZ74G1g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 7+ messages in thread
From: Fabio Estevam @ 2012-04-20  3:07 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Fabio Estevam, snijsure-4jo+YWezP1RWk0Htik3J/w,
	marek.vasut-Re5JQEeQqe8AvxtiuMwx3w,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Chris Ball

On Thu, Apr 19, 2012 at 11:59 PM, Shawn Guo <shawn.guo@linaro.org> wrote:

> We are trying to remove <mach/*.h> from drivers.  And this patch moves
> to the opposite direction.

Where would be a good location for ssp-regs.h then?

Regards,

Fabio Estevam

------------------------------------------------------------------------------
For Developers, A Lot Can Happen In A Second.
Boundary is the first to Know...and Tell You.
Monitor Your Applications in Ultra-Fine Resolution. Try it FREE!
http://p.sf.net/sfu/Boundary-d2dvs2
_______________________________________________
spi-devel-general mailing list
spi-devel-general@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] ARM: mxs: Provide a common header file for SSP controller
       [not found]         ` <CAOMZO5AOmAA93LLQnzHrOf+prH5rmNw7C-ZSpYzpKGUrZ74G1g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-04-20  3:15           ` Shawn Guo
       [not found]             ` <CAAQ0ZWSj3-wWm0HGBPwAhCzZvSxDob6w2cgb1FWzp+K=Ev5BNA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 7+ messages in thread
From: Shawn Guo @ 2012-04-20  3:15 UTC (permalink / raw)
  To: Fabio Estevam
  Cc: Fabio Estevam, snijsure-4jo+YWezP1RWk0Htik3J/w,
	marek.vasut-Re5JQEeQqe8AvxtiuMwx3w,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Chris Ball

On 20 April 2012 11:07, Fabio Estevam <festevam-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Thu, Apr 19, 2012 at 11:59 PM, Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
>
>> We are trying to remove <mach/*.h> from drivers.  And this patch moves
>> to the opposite direction.
>
> Where would be a good location for ssp-regs.h then?
>
include/linux/fsl?

Regards,
Shawn

------------------------------------------------------------------------------
For Developers, A Lot Can Happen In A Second.
Boundary is the first to Know...and Tell You.
Monitor Your Applications in Ultra-Fine Resolution. Try it FREE!
http://p.sf.net/sfu/Boundary-d2dvs2

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] spi: Add initial support for spi-mxs
       [not found]     ` <1334795434-8780-2-git-send-email-festevam-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2012-04-20  4:12       ` Shawn Guo
  0 siblings, 0 replies; 7+ messages in thread
From: Shawn Guo @ 2012-04-20  4:12 UTC (permalink / raw)
  To: Fabio Estevam
  Cc: Fabio Estevam, snijsure-4jo+YWezP1RWk0Htik3J/w,
	marek.vasut-Re5JQEeQqe8AvxtiuMwx3w,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On Wed, Apr 18, 2012 at 09:30:34PM -0300, Fabio Estevam wrote:
...
>  #define HW_SSP_VERSION				(cpu_is_mx23() ? 0x110 : 0x130)

This is something needs a bit work (as well as mxs-mmc).  The VERSION
register sits on different address between imx23 and imx28, so it loses
its point.

The cpu_is_xxx stuff does not scale for long term and will not cope
with device tree support.  We really need to get rid of it.

> +/*
> + * Freescale MXS SPI master driver
> + *
> + * Heavily based on spi-stmp.c, which is:
> + * Author: dmitry pervushin <dimka-L1vi/lXTdtvkgf6YlCu6wwC/G2K4zDHf@public.gmane.org>
> + *
> + * Copyright 2012 Freescale Semiconductor, Inc.
> + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/spi/spi.h>
> +#include <linux/err.h>
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/dma-mapping.h>

What's this for?

> +#include <linux/errno.h>
> +#include <linux/delay.h>
> +#include <mach/mxs.h>

When you get rid of the using of cpu_is_xxx, the inclusion can be
removed.

> +#include <mach/ssp-regs.h>
> +#include <mach/common.h>

With Wolfram's stmp-style devices support merged, you can save this
inclusion.

> +
> +#define SSP_TIMEOUT		200	/* 200 ms */
> +
> +#define rev_struct		(ss->version)
> +
What's this for?

> +struct mxs_spi {
> +	void __iomem *regs;	/* vaddr of the control registers */
> +
> +	u32 speed_khz;
> +	u32 divider;
> +
> +	struct clk *clk;
> +	struct device *master_dev;
> +
> +	struct work_struct work;
> +	struct workqueue_struct *workqueue;
> +	spinlock_t lock;
> +	struct list_head queue;
> +
> +	u32 version;
> +};
> +
> +static int mxs_spi_setup_transfer(struct spi_device *spi,
> +				  struct spi_transfer *t)
> +{
> +	u8 bits_per_word;
> +	u32 hz;
> +	struct mxs_spi *ss;
> +	u16 rate;
> +
> +	ss = spi_master_get_devdata(spi->master);
> +
> +	bits_per_word = spi->bits_per_word;
> +	if (t && t->bits_per_word)
> +		bits_per_word = t->bits_per_word;
> +/*
> + * Calculate speed:
> + * - by default, use maximum speed from ssp clk
> + * - if device overrides it, use it
> + * - if transfer specifies other speed, use transfer's one
> + */

Indent is missed.

> +	hz = 1000 * ss->speed_khz / ss->divider;
> +	if (spi->max_speed_hz)
> +		hz = min(hz, spi->max_speed_hz);
> +	if (t && t->speed_hz)
> +		hz = min(hz, t->speed_hz);
> +
> +	if (hz == 0) {
> +		dev_err(&spi->dev, "Cannot continue with zero clock\n");
> +		return -EINVAL;
> +	}
> +
> +	if (bits_per_word != 8) {
> +		dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
> +			__func__, bits_per_word);
> +		return -EINVAL;
> +	}
> +
> +	dev_dbg(&spi->dev, "Requested clk rate = %uHz, max = %ukHz/%d = %uHz\n",
> +		hz, ss->speed_khz, ss->divider,
> +		ss->speed_khz * 1000 / ss->divider);
> +
> +	if (ss->speed_khz * 1000 / ss->divider < hz) {
> +		dev_err(&spi->dev, "%s, unsupported clock rate %uHz\n",
> +			__func__, hz);
> +		return -EINVAL;
> +	}
> +
> +	rate = 1000 * ss->speed_khz / ss->divider / hz;
> +
> +	__raw_writel(BF_SSP_TIMING_CLOCK_DIVIDE(ss->divider) |
> +		     BF_SSP_TIMING_CLOCK_RATE(rate - 1),
> +		     ss->regs + HW_SSP_TIMING);
> +

writel or writel_relaxed?

> +	__raw_writel(BF_SSP_CTRL1_SSP_MODE(BV_SSP_CTRL1_SSP_MODE__SPI) |
> +		     BF_SSP_CTRL1_WORD_LENGTH
> +		     (BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS) |
> +		     ((spi->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) |
> +		     ((spi->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0),
> +		     ss->regs + HW_SSP_CTRL1);
> +
> +	__raw_writel(0x0, ss->regs + HW_SSP_CMD0_SET);
> +
> +	return 0;
> +}
> +
> +static void mxs_spi_cleanup(struct spi_device *spi)
> +{
> +	return;
> +}
> +
> +/* the spi->mode bits understood by this driver: */
> +#define MODEBITS (SPI_CPOL | SPI_CPHA)
> +static int mxs_spi_setup(struct spi_device *spi)
> +{
> +	struct mxs_spi *ss;
> +	int err = 0;
> +
> +	ss = spi_master_get_devdata(spi->master);
> +
> +	if (!spi->bits_per_word)
> +		spi->bits_per_word = 8;
> +
> +	if (spi->mode & ~MODEBITS)
> +		return -EINVAL;
> +
> +	err = mxs_spi_setup_transfer(spi, NULL);
> +	if (err)
> +		dev_err(&spi->dev, "Failed to setup transfer: %d\n", err);
> +
> +	return err;
> +}
> +
> +static inline u32 mxs_spi_cs(unsigned cs)
> +{
> +	return ((cs & 1) ? BM_SSP_CTRL0_WAIT_FOR_CMD : 0) |
> +	    ((cs & 2) ? BM_SSP_CTRL0_WAIT_FOR_IRQ : 0);
> +}
> +
> +static inline void mxs_spi_enable(struct mxs_spi *ss)
> +{
> +	__raw_writel(BM_SSP_CTRL0_LOCK_CS, ss->regs + HW_SSP_CTRL0_SET);
> +	__raw_writel(BM_SSP_CTRL0_IGNORE_CRC, ss->regs + HW_SSP_CTRL0_CLR);
> +}
> +
> +static inline void mxs_spi_disable(struct mxs_spi *ss)
> +{
> +	__raw_writel(BM_SSP_CTRL0_LOCK_CS, ss->regs + HW_SSP_CTRL0_CLR);
> +	__raw_writel(BM_SSP_CTRL0_IGNORE_CRC, ss->regs + HW_SSP_CTRL0_SET);
> +}
> +
> +int mxs_ssp_wait_set(struct mxs_spi *ss, int offset, int mask)

static?

> +{
> +	unsigned long timeout = jiffies + msecs_to_jiffies(SSP_TIMEOUT);
> +
> +	while (!(readl_relaxed(&ss->regs + offset) & mask)) {
> +		udelay(1);
> +		if (time_after(jiffies, timeout))
> +			return -ETIMEDOUT;
> +	}
> +	return 0;
> +}
> +
> +int mxs_ssp_wait_clr(struct mxs_spi *ss, int offset, int mask)

ditto

> +{
> +	unsigned long timeout = jiffies + msecs_to_jiffies(SSP_TIMEOUT);
> +
> +	while ((readl_relaxed(&ss->regs + offset) & mask)) {
> +		udelay(1);
> +		if (time_after(jiffies, timeout))
> +			return -ETIMEDOUT;
> +	}
> +	return 0;
> +}
> +
> +static int mxs_spi_txrx_pio(struct mxs_spi *ss, int cs,
> +			    unsigned char *buf, int len,
> +			    int *first, int *last, int write)
> +{
> +	if (*first) {
> +		mxs_spi_enable(ss);
> +		*first = 0;
> +	}
> +
> +	__raw_writel(mxs_spi_cs(cs), ss->regs + HW_SSP_CTRL0_SET);
> +
> +	while (len--) {
> +		if (*last && len == 0) {
> +			mxs_spi_disable(ss);
> +			*last = 0;
> +		}
> +
> +		if (ss->version > 3) {
> +			__raw_writel(1, ss->regs + HW_SSP_XFER_SIZE);
> +		} else {
> +			__raw_writel(BM_SSP_CTRL0_XFER_COUNT,
> +				     ss->regs + HW_SSP_CTRL0_CLR);
> +			__raw_writel(1, ss->regs + HW_SSP_CTRL0_SET);
> +		}
> +
> +		if (write)
> +			__raw_writel(BM_SSP_CTRL0_READ,
> +				     ss->regs + HW_SSP_CTRL0_CLR);
> +		else
> +			__raw_writel(BM_SSP_CTRL0_READ,
> +				     ss->regs + HW_SSP_CTRL0_SET);
> +
> +		 /* Activate Run bit */
> +		__raw_writel(BM_SSP_CTRL0_RUN, ss->regs + HW_SSP_CTRL0_SET);
> +
> +
> +		if (mxs_ssp_wait_set(ss->regs, HW_SSP_CTRL0, BM_SSP_CTRL0_RUN))
> +			return -ETIMEDOUT;

It should return what mxs_ssp_wait_set() returns.

> +
> +		if (write)
> +			__raw_writel(*buf, ss->regs + HW_SSP_DATA);
> +
> +		/* Set TRANSFER */
> +		__raw_writel(BM_SSP_CTRL0_DATA_XFER,
> +			     ss->regs + HW_SSP_CTRL0_SET);
> +
> +		if (!write) {
> +			if (mxs_ssp_wait_clr(ss->regs, HW_SSP_STATUS,
> +						BM_SSP_STATUS_FIFO_EMPTY))
> +				return -ETIMEDOUT;
> +
> +			*buf = (__raw_readl(ss->regs + HW_SSP_DATA) & 0xFF);
> +		}
> +
> +		if (mxs_ssp_wait_clr(ss->regs, HW_SSP_CTRL0, BM_SSP_CTRL0_RUN))
> +			return -ETIMEDOUT;
> +		/* advance to the next byte */
> +		buf++;
> +	}
> +	return len < 0 ? 0 : -ETIMEDOUT;
> +}
> +
> +static int mxs_spi_handle_message(struct mxs_spi *ss, struct spi_message *m)
> +{
> +	int first, last;
> +	struct spi_transfer *t, *tmp_t;
> +	int status = 0;
> +	int cs;
> +
> +	first = last = 0;
> +
> +	cs = m->spi->chip_select;
> +
> +	list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) {
> +
> +		mxs_spi_setup_transfer(m->spi, t);
> +
> +		if (&t->transfer_list == m->transfers.next)
> +			first = !0;

Use bool for first and last?

> +		if (&t->transfer_list == m->transfers.prev)
> +			last = !0;
> +		if (t->rx_buf && t->tx_buf) {
> +			pr_debug("%s: cannot send and receive simultaneously\n",
> +				 __func__);

Manage to use dev_dbg?

> +			return -EINVAL;
> +		}
> +		/*
> +		 *  REVISIT:
> +		 *  here driver completely ignores setting of t->cs_change
> +		 */
> +		if (t->tx_buf)
> +			status = mxs_spi_txrx_pio(ss, cs, (void *)t->tx_buf,

Why the cast?

> +					     t->len, &first, &last, 1);
> +		if (t->rx_buf)
> +			status = mxs_spi_txrx_pio(ss, cs, t->rx_buf,
> +					     t->len, &first, &last, 0);
> +		m->actual_length += t->len;
> +		if (status)
> +			break;
> +
> +		first = last = 0;
> +	}
> +	return status;
> +}
> +
> +/*
> + * mxs_spi_handle
> + *
> + * The workhorse of the driver - it handles messages from the list
> + */
> +static void mxs_spi_handle(struct work_struct *w)
> +{
> +	struct mxs_spi *ss = container_of(w, struct mxs_spi, work);
> +	unsigned long flags;
> +	struct spi_message *m;
> +
> +	BUG_ON(w == NULL);
> +
> +	spin_lock_irqsave(&ss->lock, flags);
> +	while (!list_empty(&ss->queue)) {
> +		m = list_entry(ss->queue.next, struct spi_message, queue);
> +		list_del_init(&m->queue);
> +		spin_unlock_irqrestore(&ss->lock, flags);
> +
> +		m->status = mxs_spi_handle_message(ss, m);
> +		if (m->complete)
> +			m->complete(m->context);
> +
> +		spin_lock_irqsave(&ss->lock, flags);
> +	}
> +	spin_unlock_irqrestore(&ss->lock, flags);
> +
> +	return;
> +}
> +
> +/*
> + * mxs_spi_transfer
> + *
> + * Called indirectly from spi_async, queues all the messages to
> + * spi_handle_message
> + *
> + */
> +static int mxs_spi_transfer(struct spi_device *spi, struct spi_message *m)
> +{
> +	struct mxs_spi *ss = spi_master_get_devdata(spi->master);
> +	unsigned long flags;
> +
> +	m->actual_length = 0;
> +	m->status = -EINPROGRESS;
> +	spin_lock_irqsave(&ss->lock, flags);
> +	list_add_tail(&m->queue, &ss->queue);
> +	queue_work(ss->workqueue, &ss->work);
> +	spin_unlock_irqrestore(&ss->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int __devinit mxs_spi_probe(struct platform_device *dev)

We usually name it pdev.

> +{
> +	int ret;
> +	struct spi_master *master;
> +	struct mxs_spi *ss;
> +	struct resource *res;
> +
> +	master = spi_alloc_master(&dev->dev, sizeof(struct mxs_spi));

sizeof(*ss)

> +	ss = spi_master_get_devdata(master);
> +	ss->master_dev = &dev->dev;
> +
> +	if (!master)
> +		return -ENOMEM;
> +
Shouldn't the check be put right after spi_alloc_master call?

> +	platform_set_drvdata(dev, master);
> +
> +	INIT_WORK(&ss->work, mxs_spi_handle);
> +	INIT_LIST_HEAD(&ss->queue);
> +	spin_lock_init(&ss->lock);
> +	ss->workqueue = create_singlethread_workqueue(dev_name(&dev->dev));
...
> +	master->transfer = mxs_spi_transfer;
> +	master->setup = mxs_spi_setup;
> +	master->cleanup = mxs_spi_cleanup;
> +	master->mode_bits = MODEBITS;
> +
It makes more sense to move this new line to above.

> +	master->bus_num = dev->id;
> +	master->num_chipselect = 1;
> +
> +	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENOENT;
> +
We do not have to check that.  We can pass whatever we get from
platform_get_resource into devm_request_and_ioremap, and the latter
will do sanity check.

> +	ss->regs = devm_request_and_ioremap(&dev->dev, res);
> +	if (!ss->regs)
> +		return -EBUSY;
The kernel doc of devm_request_and_ioremap suggests -EADDRNOTAVAIL.
> +
> +	mxs_reset_block(ss->regs);
> +	ss->clk = clk_get(&dev->dev, NULL);
> +	if (IS_ERR(ss->clk)) {
> +		ret = PTR_ERR(ss->clk);
> +		dev_err(&dev->dev, "cannot get spi clk\n");

Put ret into the message?

> +		goto out_put_master;
> +	}
> +
> +	clk_prepare_enable(ss->clk);
> +
> +	ss->speed_khz = clk_get_rate(ss->clk) / 1000;
> +	ss->divider = 2;
> +	dev_dbg(&dev->dev, "Max possible speed %d = %ld/%d kHz\n",
> +		 ss->speed_khz, clk_get_rate(ss->clk), ss->divider);
> +
> +	ss->version = __raw_readl(ss->regs + HW_SSP_VERSION) >> 24;
> +
> +	ret = spi_register_master(master);
> +	if (ret) {
> +		dev_err(&dev->dev, "cannot register spi master, %d\n", ret);
> +		goto out_clk_put;
> +	}
> +
> +	dev_info(&dev->dev, "driver probed\n");
> +
> +	return 0;
> +
> +out_clk_put:
> +	clk_disable_unprepare(ss->clk);
> +	clk_put(ss->clk);
> +out_put_master:
> +	spi_master_put(master);
> +	if (ss->workqueue)
> +		destroy_workqueue(ss->workqueue);
> +	platform_set_drvdata(dev, NULL);

I'm wondering if this is really needed.

> +
> +	return ret;
> +}
> +
> +static int __devexit mxs_spi_remove(struct platform_device *dev)
> +{
> +	struct mxs_spi *ss;
> +	struct spi_master *master;
> +
> +	master = platform_get_drvdata(dev);
> +	if (!master)
> +		goto out0;

Will we ever run into this error?

> +	ss = spi_master_get_devdata(master);
> +
> +	clk_disable_unprepare(ss->clk);
> +	clk_put(ss->clk);
> +	spi_unregister_master(master);
> +
> +	destroy_workqueue(ss->workqueue);
> +	spi_master_put(master);
> +	platform_set_drvdata(dev, NULL);
> +out0:
> +	return 0;
> +}
> +
> +static struct platform_driver mxs_spi_driver = {
> +	.probe = mxs_spi_probe,
> +	.remove = __devexit_p(mxs_spi_remove),
> +	.driver = {
> +		   .name = "mxs-spi",
> +		   .owner = THIS_MODULE,
> +		   },

Strange indent.

Regards,
Shawn

> +};
> +module_platform_driver(mxs_spi_driver);
> +
> +MODULE_AUTHOR("dmitry pervushin <dimka-L1vi/lXTdtvkgf6YlCu6wwC/G2K4zDHf@public.gmane.org>");
> +MODULE_AUTHOR("Fabio Estevam <fabio.estevam-KZfg59tc24xl57MIdRCFDg@public.gmane.org");
> +MODULE_DESCRIPTION("MXS SPI master driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:mxs-spi");
> -- 
> 1.7.1
> 

------------------------------------------------------------------------------
For Developers, A Lot Can Happen In A Second.
Boundary is the first to Know...and Tell You.
Monitor Your Applications in Ultra-Fine Resolution. Try it FREE!
http://p.sf.net/sfu/Boundary-d2dvs2

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] ARM: mxs: Provide a common header file for SSP controller
       [not found]             ` <CAAQ0ZWSj3-wWm0HGBPwAhCzZvSxDob6w2cgb1FWzp+K=Ev5BNA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2012-04-20 16:30               ` Marek Vasut
  0 siblings, 0 replies; 7+ messages in thread
From: Marek Vasut @ 2012-04-20 16:30 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Fabio Estevam, snijsure-4jo+YWezP1RWk0Htik3J/w,
	kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Chris Ball,
	Fabio Estevam

Dear Shawn Guo,

> On 20 April 2012 11:07, Fabio Estevam <festevam-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> > On Thu, Apr 19, 2012 at 11:59 PM, Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> >> We are trying to remove <mach/*.h> from drivers.  And this patch moves
> >> to the opposite direction.
> > 
> > Where would be a good location for ssp-regs.h then?
> 
> include/linux/fsl?

Funny, I recall how linux folks were moving all include/asm-arm/ stuff into 
arch/arm and now you're going on the opposite direction ? :-)

> 
> Regards,
> Shawn

Best regards,
Marek Vasut

------------------------------------------------------------------------------
For Developers, A Lot Can Happen In A Second.
Boundary is the first to Know...and Tell You.
Monitor Your Applications in Ultra-Fine Resolution. Try it FREE!
http://p.sf.net/sfu/Boundary-d2dvs2

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2012-04-20 16:30 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-19  0:30 [PATCH 1/2] ARM: mxs: Provide a common header file for SSP controller Fabio Estevam
     [not found] ` <1334795434-8780-1-git-send-email-festevam-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2012-04-19  0:30   ` [PATCH 2/2] spi: Add initial support for spi-mxs Fabio Estevam
     [not found]     ` <1334795434-8780-2-git-send-email-festevam-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2012-04-20  4:12       ` Shawn Guo
2012-04-20  2:59   ` [PATCH 1/2] ARM: mxs: Provide a common header file for SSP controller Shawn Guo
     [not found]     ` <20120420025918.GI22219-rvtDTF3kK1ictlrPMvKcciBecyulp+rMXqFh9Ls21Oc@public.gmane.org>
2012-04-20  3:07       ` Fabio Estevam
     [not found]         ` <CAOMZO5AOmAA93LLQnzHrOf+prH5rmNw7C-ZSpYzpKGUrZ74G1g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-04-20  3:15           ` Shawn Guo
     [not found]             ` <CAAQ0ZWSj3-wWm0HGBPwAhCzZvSxDob6w2cgb1FWzp+K=Ev5BNA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-04-20 16:30               ` Marek Vasut

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).