[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