diff options
Diffstat (limited to 'drivers/spi/spi-omap2-mcspi.c')
-rw-r--r-- | drivers/spi/spi-omap2-mcspi.c | 64 |
1 files changed, 44 insertions, 20 deletions
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 94f133cb2770..2941c5b96ebc 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/platform_data/spi-omap2-mcspi.h> | 44 | #include <linux/platform_data/spi-omap2-mcspi.h> |
45 | 45 | ||
46 | #define OMAP2_MCSPI_MAX_FREQ 48000000 | 46 | #define OMAP2_MCSPI_MAX_FREQ 48000000 |
47 | #define OMAP2_MCSPI_MAX_DIVIDER 4096 | ||
47 | #define OMAP2_MCSPI_MAX_FIFODEPTH 64 | 48 | #define OMAP2_MCSPI_MAX_FIFODEPTH 64 |
48 | #define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF | 49 | #define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF |
49 | #define SPI_AUTOSUSPEND_TIMEOUT 2000 | 50 | #define SPI_AUTOSUSPEND_TIMEOUT 2000 |
@@ -88,6 +89,7 @@ | |||
88 | #define OMAP2_MCSPI_CHCONF_FORCE BIT(20) | 89 | #define OMAP2_MCSPI_CHCONF_FORCE BIT(20) |
89 | #define OMAP2_MCSPI_CHCONF_FFET BIT(27) | 90 | #define OMAP2_MCSPI_CHCONF_FFET BIT(27) |
90 | #define OMAP2_MCSPI_CHCONF_FFER BIT(28) | 91 | #define OMAP2_MCSPI_CHCONF_FFER BIT(28) |
92 | #define OMAP2_MCSPI_CHCONF_CLKG BIT(29) | ||
91 | 93 | ||
92 | #define OMAP2_MCSPI_CHSTAT_RXS BIT(0) | 94 | #define OMAP2_MCSPI_CHSTAT_RXS BIT(0) |
93 | #define OMAP2_MCSPI_CHSTAT_TXS BIT(1) | 95 | #define OMAP2_MCSPI_CHSTAT_TXS BIT(1) |
@@ -95,6 +97,7 @@ | |||
95 | #define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3) | 97 | #define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3) |
96 | 98 | ||
97 | #define OMAP2_MCSPI_CHCTRL_EN BIT(0) | 99 | #define OMAP2_MCSPI_CHCTRL_EN BIT(0) |
100 | #define OMAP2_MCSPI_CHCTRL_EXTCLK_MASK (0xff << 8) | ||
98 | 101 | ||
99 | #define OMAP2_MCSPI_WAKEUPENABLE_WKEN BIT(0) | 102 | #define OMAP2_MCSPI_WAKEUPENABLE_WKEN BIT(0) |
100 | 103 | ||
@@ -148,7 +151,7 @@ struct omap2_mcspi_cs { | |||
148 | int word_len; | 151 | int word_len; |
149 | struct list_head node; | 152 | struct list_head node; |
150 | /* Context save and restore shadow register */ | 153 | /* Context save and restore shadow register */ |
151 | u32 chconf0; | 154 | u32 chconf0, chctrl0; |
152 | }; | 155 | }; |
153 | 156 | ||
154 | static inline void mcspi_write_reg(struct spi_master *master, | 157 | static inline void mcspi_write_reg(struct spi_master *master, |
@@ -229,10 +232,16 @@ static void omap2_mcspi_set_dma_req(const struct spi_device *spi, | |||
229 | 232 | ||
230 | static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable) | 233 | static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable) |
231 | { | 234 | { |
235 | struct omap2_mcspi_cs *cs = spi->controller_state; | ||
232 | u32 l; | 236 | u32 l; |
233 | 237 | ||
234 | l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0; | 238 | l = cs->chctrl0; |
235 | mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l); | 239 | if (enable) |
240 | l |= OMAP2_MCSPI_CHCTRL_EN; | ||
241 | else | ||
242 | l &= ~OMAP2_MCSPI_CHCTRL_EN; | ||
243 | cs->chctrl0 = l; | ||
244 | mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0); | ||
236 | /* Flash post-writes */ | 245 | /* Flash post-writes */ |
237 | mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0); | 246 | mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0); |
238 | } | 247 | } |
@@ -839,7 +848,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, | |||
839 | struct omap2_mcspi_cs *cs = spi->controller_state; | 848 | struct omap2_mcspi_cs *cs = spi->controller_state; |
840 | struct omap2_mcspi *mcspi; | 849 | struct omap2_mcspi *mcspi; |
841 | struct spi_master *spi_cntrl; | 850 | struct spi_master *spi_cntrl; |
842 | u32 l = 0, div = 0; | 851 | u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0; |
843 | u8 word_len = spi->bits_per_word; | 852 | u8 word_len = spi->bits_per_word; |
844 | u32 speed_hz = spi->max_speed_hz; | 853 | u32 speed_hz = spi->max_speed_hz; |
845 | 854 | ||
@@ -855,7 +864,17 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, | |||
855 | speed_hz = t->speed_hz; | 864 | speed_hz = t->speed_hz; |
856 | 865 | ||
857 | speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ); | 866 | speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ); |
858 | div = omap2_mcspi_calc_divisor(speed_hz); | 867 | if (speed_hz < (OMAP2_MCSPI_MAX_FREQ / OMAP2_MCSPI_MAX_DIVIDER)) { |
868 | clkd = omap2_mcspi_calc_divisor(speed_hz); | ||
869 | speed_hz = OMAP2_MCSPI_MAX_FREQ >> clkd; | ||
870 | clkg = 0; | ||
871 | } else { | ||
872 | div = (OMAP2_MCSPI_MAX_FREQ + speed_hz - 1) / speed_hz; | ||
873 | speed_hz = OMAP2_MCSPI_MAX_FREQ / div; | ||
874 | clkd = (div - 1) & 0xf; | ||
875 | extclk = (div - 1) >> 4; | ||
876 | clkg = OMAP2_MCSPI_CHCONF_CLKG; | ||
877 | } | ||
859 | 878 | ||
860 | l = mcspi_cached_chconf0(spi); | 879 | l = mcspi_cached_chconf0(spi); |
861 | 880 | ||
@@ -884,7 +903,16 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, | |||
884 | 903 | ||
885 | /* set clock divisor */ | 904 | /* set clock divisor */ |
886 | l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK; | 905 | l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK; |
887 | l |= div << 2; | 906 | l |= clkd << 2; |
907 | |||
908 | /* set clock granularity */ | ||
909 | l &= ~OMAP2_MCSPI_CHCONF_CLKG; | ||
910 | l |= clkg; | ||
911 | if (clkg) { | ||
912 | cs->chctrl0 &= ~OMAP2_MCSPI_CHCTRL_EXTCLK_MASK; | ||
913 | cs->chctrl0 |= extclk << 8; | ||
914 | mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0); | ||
915 | } | ||
888 | 916 | ||
889 | /* set SPI mode 0..3 */ | 917 | /* set SPI mode 0..3 */ |
890 | if (spi->mode & SPI_CPOL) | 918 | if (spi->mode & SPI_CPOL) |
@@ -899,7 +927,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, | |||
899 | mcspi_write_chconf0(spi, l); | 927 | mcspi_write_chconf0(spi, l); |
900 | 928 | ||
901 | dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n", | 929 | dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n", |
902 | OMAP2_MCSPI_MAX_FREQ >> div, | 930 | speed_hz, |
903 | (spi->mode & SPI_CPHA) ? "trailing" : "leading", | 931 | (spi->mode & SPI_CPHA) ? "trailing" : "leading", |
904 | (spi->mode & SPI_CPOL) ? "inverted" : "normal"); | 932 | (spi->mode & SPI_CPOL) ? "inverted" : "normal"); |
905 | 933 | ||
@@ -971,6 +999,7 @@ static int omap2_mcspi_setup(struct spi_device *spi) | |||
971 | cs->base = mcspi->base + spi->chip_select * 0x14; | 999 | cs->base = mcspi->base + spi->chip_select * 0x14; |
972 | cs->phys = mcspi->phys + spi->chip_select * 0x14; | 1000 | cs->phys = mcspi->phys + spi->chip_select * 0x14; |
973 | cs->chconf0 = 0; | 1001 | cs->chconf0 = 0; |
1002 | cs->chctrl0 = 0; | ||
974 | spi->controller_state = cs; | 1003 | spi->controller_state = cs; |
975 | /* Link this to context save list */ | 1004 | /* Link this to context save list */ |
976 | list_add_tail(&cs->node, &ctx->cs); | 1005 | list_add_tail(&cs->node, &ctx->cs); |
@@ -1056,12 +1085,15 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) | |||
1056 | status = -EINVAL; | 1085 | status = -EINVAL; |
1057 | break; | 1086 | break; |
1058 | } | 1087 | } |
1059 | if (par_override || t->speed_hz || t->bits_per_word) { | 1088 | if (par_override || |
1089 | (t->speed_hz != spi->max_speed_hz) || | ||
1090 | (t->bits_per_word != spi->bits_per_word)) { | ||
1060 | par_override = 1; | 1091 | par_override = 1; |
1061 | status = omap2_mcspi_setup_transfer(spi, t); | 1092 | status = omap2_mcspi_setup_transfer(spi, t); |
1062 | if (status < 0) | 1093 | if (status < 0) |
1063 | break; | 1094 | break; |
1064 | if (!t->speed_hz && !t->bits_per_word) | 1095 | if (t->speed_hz == spi->max_speed_hz && |
1096 | t->bits_per_word == spi->bits_per_word) | ||
1065 | par_override = 0; | 1097 | par_override = 0; |
1066 | } | 1098 | } |
1067 | if (cd && cd->cs_per_word) { | 1099 | if (cd && cd->cs_per_word) { |
@@ -1175,16 +1207,12 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, | |||
1175 | m->actual_length = 0; | 1207 | m->actual_length = 0; |
1176 | m->status = 0; | 1208 | m->status = 0; |
1177 | 1209 | ||
1178 | /* reject invalid messages and transfers */ | ||
1179 | if (list_empty(&m->transfers)) | ||
1180 | return -EINVAL; | ||
1181 | list_for_each_entry(t, &m->transfers, transfer_list) { | 1210 | list_for_each_entry(t, &m->transfers, transfer_list) { |
1182 | const void *tx_buf = t->tx_buf; | 1211 | const void *tx_buf = t->tx_buf; |
1183 | void *rx_buf = t->rx_buf; | 1212 | void *rx_buf = t->rx_buf; |
1184 | unsigned len = t->len; | 1213 | unsigned len = t->len; |
1185 | 1214 | ||
1186 | if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ | 1215 | if ((len && !(rx_buf || tx_buf))) { |
1187 | || (len && !(rx_buf || tx_buf))) { | ||
1188 | dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n", | 1216 | dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n", |
1189 | t->speed_hz, | 1217 | t->speed_hz, |
1190 | len, | 1218 | len, |
@@ -1193,12 +1221,6 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, | |||
1193 | t->bits_per_word); | 1221 | t->bits_per_word); |
1194 | return -EINVAL; | 1222 | return -EINVAL; |
1195 | } | 1223 | } |
1196 | if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) { | ||
1197 | dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n", | ||
1198 | t->speed_hz, | ||
1199 | OMAP2_MCSPI_MAX_FREQ >> 15); | ||
1200 | return -EINVAL; | ||
1201 | } | ||
1202 | 1224 | ||
1203 | if (m->is_dma_mapped || len < DMA_MIN_BYTES) | 1225 | if (m->is_dma_mapped || len < DMA_MIN_BYTES) |
1204 | continue; | 1226 | continue; |
@@ -1310,6 +1332,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev) | |||
1310 | master->transfer_one_message = omap2_mcspi_transfer_one_message; | 1332 | master->transfer_one_message = omap2_mcspi_transfer_one_message; |
1311 | master->cleanup = omap2_mcspi_cleanup; | 1333 | master->cleanup = omap2_mcspi_cleanup; |
1312 | master->dev.of_node = node; | 1334 | master->dev.of_node = node; |
1335 | master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ; | ||
1336 | master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15; | ||
1313 | 1337 | ||
1314 | platform_set_drvdata(pdev, master); | 1338 | platform_set_drvdata(pdev, master); |
1315 | 1339 | ||