[PATCH 95/133] [Jaunty SRU] ARM.imx51 Freescale:ENGR00112870 SPI: workaround for chipselect pin may not keep correct level

Brad Figg brad.figg at canonical.com
Thu Jul 9 16:49:25 UTC 2009


From: Katherine Lu <katherine.lu at freescale.com>

Workaround for ecspi chipselect pin may not keep correct level when idle.

Signed-off-by: Katherine Lu <katherine.lu at freescale.com>
Signed-off-by: Brad Figg <brad.figg at canonical.com>
---
 arch/arm/mach-mx51/devices.c          |    6 ++
 arch/arm/mach-mx51/mx51_3stack_gpio.c |   83 +++++++++++++++++++++++++++++----
 arch/arm/plat-mxc/include/mach/mxc.h  |    7 +++
 drivers/spi/mxc_spi.c                 |   59 ++++++++++++++++++++++--
 4 files changed, 141 insertions(+), 14 deletions(-)

diff --git a/arch/arm/mach-mx51/devices.c b/arch/arm/mach-mx51/devices.c
index 5b9aa9a..41466a2 100644
--- a/arch/arm/mach-mx51/devices.c
+++ b/arch/arm/mach-mx51/devices.c
@@ -431,10 +431,16 @@ static struct resource mxcspi1_resources[] = {
 	       },
 };
 
+extern void gpio_spi_chipselect_active(int cspi_mode, int status,
+				       int chipselect);
+extern void gpio_spi_chipselect_inactive(int cspi_mode, int status,
+					 int chipselect);
 /*! Platform Data for MXC CSPI1 */
 static struct mxc_spi_master mxcspi1_data = {
 	.maxchipselect = 4,
 	.spi_version = 23,
+	.chipselect_active = gpio_spi_chipselect_active,
+	.chipselect_inactive = gpio_spi_chipselect_inactive,
 };
 
 /*! Device Definition for MXC CSPI1 */
diff --git a/arch/arm/mach-mx51/mx51_3stack_gpio.c b/arch/arm/mach-mx51/mx51_3stack_gpio.c
index 9d03b70..6174db4 100644
--- a/arch/arm/mach-mx51/mx51_3stack_gpio.c
+++ b/arch/arm/mach-mx51/mx51_3stack_gpio.c
@@ -109,16 +109,6 @@ static struct mxc_iomux_pin_cfg __initdata mxc_iomux_pins[] = {
 				  PAD_CTL_SRE_FAST),
 	 },
 	{
-	 MX51_PIN_CSPI1_SS0, IOMUX_CONFIG_ALT0,
-	 (PAD_CTL_HYS_ENABLE | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH |
-				  PAD_CTL_SRE_FAST),
-	 },
-	{
-	 MX51_PIN_CSPI1_SS1, IOMUX_CONFIG_ALT0,
-	 (PAD_CTL_HYS_ENABLE | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH |
-				  PAD_CTL_SRE_FAST),
-	 },
-	{
 	 MX51_PIN_OWIRE_LINE, IOMUX_CONFIG_ALT0,
 	 (PAD_CTL_HYS_ENABLE | PAD_CTL_PKE_ENABLE |
 		 PAD_CTL_ODE_OPENDRAIN_ENABLE | PAD_CTL_DRV_HIGH |
@@ -734,3 +724,76 @@ void __init mx51_3stack_io_init(void)
 	mxc_set_gpio_dataout(MX51_PIN_DISPB2_SER_DIO, 0);
 }
 
+/* workaround for ecspi chipselect pin may not keep correct level when idle */
+void gpio_spi_chipselect_active(int cspi_mode, int status, int chipselect)
+{
+	switch (cspi_mode) {
+	case 1:
+		switch (chipselect) {
+		case 0x1:
+			mxc_request_iomux(MX51_PIN_CSPI1_SS0,
+					  IOMUX_CONFIG_ALT0);
+			mxc_iomux_set_pad(MX51_PIN_CSPI1_SS0,
+					  PAD_CTL_HYS_ENABLE |
+					  PAD_CTL_PKE_ENABLE |
+					  PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST);
+
+			mxc_request_iomux(MX51_PIN_CSPI1_SS1,
+					  IOMUX_CONFIG_GPIO);
+			mxc_set_gpio_direction(MX51_PIN_CSPI1_SS1, 0);
+			mxc_set_gpio_dataout(MX51_PIN_CSPI1_SS1, 2 & (~status));
+			break;
+		case 0x2:
+			mxc_request_iomux(MX51_PIN_CSPI1_SS1,
+					  IOMUX_CONFIG_ALT0);
+			mxc_iomux_set_pad(MX51_PIN_CSPI1_SS1,
+					  PAD_CTL_HYS_ENABLE |
+					  PAD_CTL_PKE_ENABLE |
+					  PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST);
+
+			mxc_request_iomux(MX51_PIN_CSPI1_SS0,
+					  IOMUX_CONFIG_GPIO);
+			mxc_set_gpio_direction(MX51_PIN_CSPI1_SS0, 0);
+			mxc_set_gpio_dataout(MX51_PIN_CSPI1_SS0, 1 & (~status));
+			break;
+		default:
+			break;
+		}
+		break;
+	case 2:
+		break;
+	case 3:
+		break;
+	default:
+		break;
+	}
+}
+EXPORT_SYMBOL(gpio_spi_chipselect_active);
+
+void gpio_spi_chipselect_inactive(int cspi_mode, int status, int chipselect)
+{
+	switch (cspi_mode) {
+	case 1:
+		switch (chipselect) {
+		case 0x1:
+			mxc_free_iomux(MX51_PIN_CSPI1_SS0, IOMUX_CONFIG_ALT0);
+			mxc_free_iomux(MX51_PIN_CSPI1_SS1, IOMUX_CONFIG_GPIO);
+			break;
+		case 0x2:
+			mxc_free_iomux(MX51_PIN_CSPI1_SS0, IOMUX_CONFIG_GPIO);
+			mxc_free_iomux(MX51_PIN_CSPI1_SS1, IOMUX_CONFIG_ALT0);
+			break;
+		default:
+			break;
+		}
+		break;
+	case 2:
+		break;
+	case 3:
+		break;
+	default:
+		break;
+	}
+}
+EXPORT_SYMBOL(gpio_spi_chipselect_inactive);
+
diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h
index 8318ddd..5830ce1 100644
--- a/arch/arm/plat-mxc/include/mach/mxc.h
+++ b/arch/arm/plat-mxc/include/mach/mxc.h
@@ -69,6 +69,13 @@ struct mxc_spi_master {
 	 * CSPI Hardware Version.
 	 */
 	unsigned int spi_version;
+	/*!
+	 * CSPI chipselect pin table.
+	 * Workaround for ecspi chipselect pin may not keep correct level when
+	 * idle.
+	 */
+	void (*chipselect_active) (int cspi_mode, int status, int chipselect);
+	void (*chipselect_inactive) (int cspi_mode, int status, int chipselect);
 };
 
 struct mxc_ipu_config {
diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c
index 8db014d..b3e3ef2 100644
--- a/drivers/spi/mxc_spi.c
+++ b/drivers/spi/mxc_spi.c
@@ -203,6 +203,10 @@ struct mxc_spi {
 	void *test_addr;
 	/* Reset reg address */
 	void *reset_addr;
+	/* Chipselect active function */
+	void (*chipselect_active) (int cspi_mode, int status, int chipselect);
+	/* Chipselect inactive function */
+	void (*chipselect_inactive) (int cspi_mode, int status, int chipselect);
 };
 
 #ifdef CONFIG_SPI_MXC_TEST_LOOPBACK
@@ -568,6 +572,7 @@ void mxc_spi_chipselect(struct spi_device *spi, int is_active)
 	unsigned int ctrl_reg = 0;
 	unsigned int config_reg = 0;
 	unsigned int xfer_len;
+	unsigned int cs_value;
 
 	if (is_active == BITBANG_CS_INACTIVE) {
 		/*Need to deselect the slave */
@@ -613,10 +618,19 @@ void mxc_spi_chipselect(struct spi_device *spi, int is_active)
 			      spi_ver_def->mode_mask) <<
 			     spi_ver_def->sclk_ctl_shift);
 		}
-		if (spi->mode & SPI_CS_HIGH)
+		cs_value = (__raw_readl(MXC_CSPICONFIG +
+					master_drv_data->ctrl_addr) >>
+			    spi_ver_def->ss_pol_shift) & spi_ver_def->mode_mask;
+		if (spi->mode & SPI_CS_HIGH) {
 			config_reg |=
-			    (((1 << (spi->chip_select & MXC_CSPICTRL_CSMASK)) &
-			      spi_ver_def->mode_mask) <<
+			    ((((1 << (spi->chip_select & MXC_CSPICTRL_CSMASK)) &
+			       spi_ver_def->mode_mask) | cs_value) <<
+			     spi_ver_def->ss_pol_shift);
+		} else
+			config_reg |=
+			    ((~((1 << (spi->chip_select &
+				       MXC_CSPICTRL_CSMASK)) &
+				spi_ver_def->mode_mask) & cs_value) <<
 			     spi_ver_def->ss_pol_shift);
 		config_reg |=
 		    (((1 << (spi->chip_select & MXC_CSPICTRL_CSMASK)) &
@@ -779,12 +793,23 @@ int mxc_spi_poll_transfer(struct spi_device *spi, struct spi_transfer *t)
 	volatile unsigned int status;
 	u32 rx_tmp;
 	u32 fifo_size;
+	int chipselect_status;
 
 	mxc_spi_chipselect(spi, BITBANG_CS_ACTIVE);
 
 	/* Get the master controller driver data from spi device's master */
 	master_drv_data = spi_master_get_devdata(spi->master);
 
+	chipselect_status = __raw_readl(MXC_CSPICONFIG +
+					master_drv_data->ctrl_addr);
+	chipselect_status >>= master_drv_data->spi_ver_def->ss_pol_shift &
+	    master_drv_data->spi_ver_def->mode_mask;
+	if (master_drv_data->chipselect_active)
+		master_drv_data->chipselect_active(spi->master->bus_num,
+						   chipselect_status,
+						   (spi->chip_select &
+						    MXC_CSPICTRL_CSMASK) + 1);
+
 	clk_enable(master_drv_data->clk);
 
 	/* Modify the Tx, Rx, Count */
@@ -806,7 +831,11 @@ int mxc_spi_poll_transfer(struct spi_device *spi, struct spi_transfer *t)
 	}
 
 	clk_disable(master_drv_data->clk);
-
+	if (master_drv_data->chipselect_inactive)
+		master_drv_data->chipselect_inactive(spi->master->bus_num,
+						     chipselect_status,
+						     (spi->chip_select &
+						      MXC_CSPICTRL_CSMASK) + 1);
 	return 0;
 }
 
@@ -825,12 +854,23 @@ int mxc_spi_transfer(struct spi_device *spi, struct spi_transfer *t)
 {
 	struct mxc_spi *master_drv_data = NULL;
 	int count;
+	int chipselect_status;
 	u32 fifo_size;
 
 	/* Get the master controller driver data from spi device's master */
 
 	master_drv_data = spi_master_get_devdata(spi->master);
 
+	chipselect_status = __raw_readl(MXC_CSPICONFIG +
+					master_drv_data->ctrl_addr);
+	chipselect_status >>= master_drv_data->spi_ver_def->ss_pol_shift &
+	    master_drv_data->spi_ver_def->mode_mask;
+	if (master_drv_data->chipselect_active)
+		master_drv_data->chipselect_active(spi->master->bus_num,
+						   chipselect_status,
+						   (spi->chip_select &
+						    MXC_CSPICTRL_CSMASK) + 1);
+
 	clk_enable(master_drv_data->clk);
 	/* Modify the Tx, Rx, Count */
 	master_drv_data->transfer.tx_buf = t->tx_buf;
@@ -861,6 +901,11 @@ int mxc_spi_transfer(struct spi_device *spi, struct spi_transfer *t)
 				    rx_inten_dif));
 
 	clk_disable(master_drv_data->clk);
+	if (master_drv_data->chipselect_inactive)
+		master_drv_data->chipselect_inactive(spi->master->bus_num,
+						     chipselect_status,
+						     (spi->chip_select &
+						      MXC_CSPICTRL_CSMASK) + 1);
 	return (t->len - master_drv_data->transfer.count);
 }
 
@@ -925,6 +970,12 @@ static int mxc_spi_probe(struct platform_device *pdev)
 
 	master_drv_data = spi_master_get_devdata(master);
 	master_drv_data->mxc_bitbang.master = spi_master_get(master);
+	if (mxc_platform_info->chipselect_active)
+		master_drv_data->chipselect_active =
+		    mxc_platform_info->chipselect_active;
+	if (mxc_platform_info->chipselect_inactive)
+		master_drv_data->chipselect_inactive =
+		    mxc_platform_info->chipselect_inactive;
 
 	/* Identify SPI version */
 
-- 
1.6.0.4





More information about the kernel-team mailing list