diff options
author | Tero Kristo <tero.kristo@nokia.com> | 2009-09-22 19:46:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 10:39:44 -0400 |
commit | 89c05372d08f3982eeb94d1ea22a60a5eaa8cd6d (patch) | |
tree | de8793013684032d7de9a8dbada5f466de18bf23 | |
parent | a41ae1ad907655b2efbb9b1a97736ab1451e1649 (diff) |
spi: McSPI saves CHCONFx too
Previous restore was lazy and only restored CHxCONF when it was needed by
a specific chip select. This could cause occasional errors on an SPI bus
where multiple chip selects are in use.
Signed-off-by: Tero Kristo <tero.kristo@nokia.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/spi/omap2_mcspi.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c index e96ad2709565..85b7aea73374 100644 --- a/drivers/spi/omap2_mcspi.c +++ b/drivers/spi/omap2_mcspi.c | |||
@@ -134,6 +134,7 @@ struct omap2_mcspi_cs { | |||
134 | void __iomem *base; | 134 | void __iomem *base; |
135 | unsigned long phys; | 135 | unsigned long phys; |
136 | int word_len; | 136 | int word_len; |
137 | struct list_head node; | ||
137 | /* Context save and restore shadow register */ | 138 | /* Context save and restore shadow register */ |
138 | u32 chconf0; | 139 | u32 chconf0; |
139 | }; | 140 | }; |
@@ -145,6 +146,7 @@ struct omap2_mcspi_regs { | |||
145 | u32 sysconfig; | 146 | u32 sysconfig; |
146 | u32 modulctrl; | 147 | u32 modulctrl; |
147 | u32 wakeupenable; | 148 | u32 wakeupenable; |
149 | struct list_head cs; | ||
148 | }; | 150 | }; |
149 | 151 | ||
150 | static struct omap2_mcspi_regs omap2_mcspi_ctx[OMAP2_MCSPI_MAX_CTRL]; | 152 | static struct omap2_mcspi_regs omap2_mcspi_ctx[OMAP2_MCSPI_MAX_CTRL]; |
@@ -255,6 +257,7 @@ static void omap2_mcspi_set_master_mode(struct spi_master *master) | |||
255 | static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) | 257 | static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) |
256 | { | 258 | { |
257 | struct spi_master *spi_cntrl; | 259 | struct spi_master *spi_cntrl; |
260 | struct omap2_mcspi_cs *cs; | ||
258 | spi_cntrl = mcspi->master; | 261 | spi_cntrl = mcspi->master; |
259 | 262 | ||
260 | /* McSPI: context restore */ | 263 | /* McSPI: context restore */ |
@@ -266,6 +269,10 @@ static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) | |||
266 | 269 | ||
267 | mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE, | 270 | mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE, |
268 | omap2_mcspi_ctx[spi_cntrl->bus_num - 1].wakeupenable); | 271 | omap2_mcspi_ctx[spi_cntrl->bus_num - 1].wakeupenable); |
272 | |||
273 | list_for_each_entry(cs, &omap2_mcspi_ctx[spi_cntrl->bus_num - 1].cs, | ||
274 | node) | ||
275 | __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); | ||
269 | } | 276 | } |
270 | static void omap2_mcspi_disable_clocks(struct omap2_mcspi *mcspi) | 277 | static void omap2_mcspi_disable_clocks(struct omap2_mcspi *mcspi) |
271 | { | 278 | { |
@@ -714,6 +721,9 @@ static int omap2_mcspi_setup(struct spi_device *spi) | |||
714 | cs->phys = mcspi->phys + spi->chip_select * 0x14; | 721 | cs->phys = mcspi->phys + spi->chip_select * 0x14; |
715 | cs->chconf0 = 0; | 722 | cs->chconf0 = 0; |
716 | spi->controller_state = cs; | 723 | spi->controller_state = cs; |
724 | /* Link this to context save list */ | ||
725 | list_add_tail(&cs->node, | ||
726 | &omap2_mcspi_ctx[mcspi->master->bus_num - 1].cs); | ||
717 | } | 727 | } |
718 | 728 | ||
719 | if (mcspi_dma->dma_rx_channel == -1 | 729 | if (mcspi_dma->dma_rx_channel == -1 |
@@ -736,10 +746,15 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) | |||
736 | { | 746 | { |
737 | struct omap2_mcspi *mcspi; | 747 | struct omap2_mcspi *mcspi; |
738 | struct omap2_mcspi_dma *mcspi_dma; | 748 | struct omap2_mcspi_dma *mcspi_dma; |
749 | struct omap2_mcspi_cs *cs; | ||
739 | 750 | ||
740 | mcspi = spi_master_get_devdata(spi->master); | 751 | mcspi = spi_master_get_devdata(spi->master); |
741 | mcspi_dma = &mcspi->dma_channels[spi->chip_select]; | 752 | mcspi_dma = &mcspi->dma_channels[spi->chip_select]; |
742 | 753 | ||
754 | /* Unlink controller state from context save list */ | ||
755 | cs = spi->controller_state; | ||
756 | list_del(&cs->node); | ||
757 | |||
743 | kfree(spi->controller_state); | 758 | kfree(spi->controller_state); |
744 | 759 | ||
745 | if (mcspi_dma->dma_rx_channel != -1) { | 760 | if (mcspi_dma->dma_rx_channel != -1) { |
@@ -1104,6 +1119,7 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev) | |||
1104 | 1119 | ||
1105 | spin_lock_init(&mcspi->lock); | 1120 | spin_lock_init(&mcspi->lock); |
1106 | INIT_LIST_HEAD(&mcspi->msg_queue); | 1121 | INIT_LIST_HEAD(&mcspi->msg_queue); |
1122 | INIT_LIST_HEAD(&omap2_mcspi_ctx[master->bus_num - 1].cs); | ||
1107 | 1123 | ||
1108 | mcspi->ick = clk_get(&pdev->dev, "ick"); | 1124 | mcspi->ick = clk_get(&pdev->dev, "ick"); |
1109 | if (IS_ERR(mcspi->ick)) { | 1125 | if (IS_ERR(mcspi->ick)) { |