Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Add multi mode support for omap-mcspi

Merge series from Louis Chauvet <louis.chauvet@bootlin.com>:

This series adds the support for the omap-mcspi multi mode which allows
sending SPI messages with a shorter delay between CS and the message.

One drawback of the multi-mode is that the CS is raised between each word,
so it can only be used with messages containing 1 word transfers and
asking for cs_change. Few devices, like FPGAs, may easily workaround this
limitation.

The first patch removes the current implementation, which is working, but
don't comply with what is asked in the spi transfer (The CS is raised by
the hardware regardless of cs_change state). No drivers or board file use this
implementation upstream.

The second patch adds the implementation of the multi-mode, which complies
with what is asked in the SPI message.

The third patch is the suggested optimization for using MULTI mode in more
situations.

+74 -24
+74 -21
drivers/spi/spi-omap2-mcspi.c
··· 131 131 unsigned int pin_dir:1; 132 132 size_t max_xfer_len; 133 133 u32 ref_clk_hz; 134 + bool use_multi_mode; 134 135 }; 135 136 136 137 struct omap2_mcspi_cs { ··· 257 256 258 257 l = mcspi_cached_chconf0(spi); 259 258 260 - if (enable) 259 + /* Only enable chip select manually if single mode is used */ 260 + if (mcspi->use_multi_mode) { 261 261 l &= ~OMAP2_MCSPI_CHCONF_FORCE; 262 - else 263 - l |= OMAP2_MCSPI_CHCONF_FORCE; 262 + } else { 263 + if (enable) 264 + l &= ~OMAP2_MCSPI_CHCONF_FORCE; 265 + else 266 + l |= OMAP2_MCSPI_CHCONF_FORCE; 267 + } 264 268 265 269 mcspi_write_chconf0(spi, l); 266 270 ··· 289 283 l |= (OMAP2_MCSPI_MODULCTRL_MS); 290 284 } else { 291 285 l &= ~(OMAP2_MCSPI_MODULCTRL_MS); 292 - l |= OMAP2_MCSPI_MODULCTRL_SINGLE; 286 + 287 + /* Enable single mode if needed */ 288 + if (mcspi->use_multi_mode) 289 + l &= ~OMAP2_MCSPI_MODULCTRL_SINGLE; 290 + else 291 + l |= OMAP2_MCSPI_MODULCTRL_SINGLE; 293 292 } 294 293 mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, l); 295 294 ··· 1186 1175 t->bits_per_word == spi->bits_per_word) 1187 1176 par_override = 0; 1188 1177 } 1189 - if (cd && cd->cs_per_word) { 1190 - chconf = mcspi->ctx.modulctrl; 1191 - chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE; 1192 - mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, chconf); 1193 - mcspi->ctx.modulctrl = 1194 - mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL); 1195 - } 1196 1178 1197 1179 chconf = mcspi_cached_chconf0(spi); 1198 1180 chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK; ··· 1244 1240 status = omap2_mcspi_setup_transfer(spi, NULL); 1245 1241 } 1246 1242 1247 - if (cd && cd->cs_per_word) { 1248 - chconf = mcspi->ctx.modulctrl; 1249 - chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE; 1250 - mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, chconf); 1251 - mcspi->ctx.modulctrl = 1252 - mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL); 1253 - } 1254 - 1255 1243 omap2_mcspi_set_enable(spi, 0); 1256 1244 1257 1245 if (spi_get_csgpiod(spi, 0)) ··· 1261 1265 struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr); 1262 1266 struct omap2_mcspi_regs *ctx = &mcspi->ctx; 1263 1267 struct omap2_mcspi_cs *cs; 1268 + struct spi_transfer *tr; 1269 + u8 bits_per_word; 1264 1270 1265 - /* Only a single channel can have the FORCE bit enabled 1271 + /* 1272 + * The conditions are strict, it is mandatory to check each transfer of the list to see if 1273 + * multi-mode is applicable. 1274 + */ 1275 + mcspi->use_multi_mode = true; 1276 + list_for_each_entry(tr, &msg->transfers, transfer_list) { 1277 + if (!tr->bits_per_word) 1278 + bits_per_word = msg->spi->bits_per_word; 1279 + else 1280 + bits_per_word = tr->bits_per_word; 1281 + 1282 + /* 1283 + * Check if this transfer contains only one word; 1284 + * OR contains 1 to 4 words, with bits_per_word == 8 and no delay between each word 1285 + * OR contains 1 to 2 words, with bits_per_word == 16 and no delay between each word 1286 + * 1287 + * If one of the two last case is true, this also change the bits_per_word of this 1288 + * transfer to make it a bit faster. 1289 + * It's not an issue to change the bits_per_word here even if the multi-mode is not 1290 + * applicable for this message, the signal on the wire will be the same. 1291 + */ 1292 + if (bits_per_word < 8 && tr->len == 1) { 1293 + /* multi-mode is applicable, only one word (1..7 bits) */ 1294 + } else if (tr->word_delay.value == 0 && bits_per_word == 8 && tr->len <= 4) { 1295 + /* multi-mode is applicable, only one "bigger" word (8,16,24,32 bits) */ 1296 + tr->bits_per_word = tr->len * bits_per_word; 1297 + } else if (tr->word_delay.value == 0 && bits_per_word == 16 && tr->len <= 2) { 1298 + /* multi-mode is applicable, only one "bigger" word (16,32 bits) */ 1299 + tr->bits_per_word = tr->len * bits_per_word / 2; 1300 + } else if (bits_per_word >= 8 && tr->len == bits_per_word / 8) { 1301 + /* multi-mode is applicable, only one word (9..15,17..32 bits) */ 1302 + } else { 1303 + /* multi-mode is not applicable: more than one word in the transfer */ 1304 + mcspi->use_multi_mode = false; 1305 + } 1306 + 1307 + /* Check if transfer asks to change the CS status after the transfer */ 1308 + if (!tr->cs_change) 1309 + mcspi->use_multi_mode = false; 1310 + 1311 + /* 1312 + * If at least one message is not compatible, switch back to single mode 1313 + * 1314 + * The bits_per_word of certain transfer can be different, but it will have no 1315 + * impact on the signal itself. 1316 + */ 1317 + if (!mcspi->use_multi_mode) 1318 + break; 1319 + } 1320 + 1321 + omap2_mcspi_set_mode(ctlr); 1322 + 1323 + /* In single mode only a single channel can have the FORCE bit enabled 1266 1324 * in its chconf0 register. 1267 1325 * Scan all channels and disable them except the current one. 1268 1326 * A FORCE can remain from a last transfer having cs_change enabled 1327 + * 1328 + * In multi mode all FORCE bits must be disabled. 1269 1329 */ 1270 1330 list_for_each_entry(cs, &ctx->cs, node) { 1271 - if (msg->spi->controller_state == cs) 1331 + if (msg->spi->controller_state == cs && !mcspi->use_multi_mode) { 1272 1332 continue; 1333 + } 1273 1334 1274 1335 if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE)) { 1275 1336 cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE;
-3
include/linux/platform_data/spi-omap2-mcspi.h
··· 16 16 17 17 struct omap2_mcspi_device_config { 18 18 unsigned turbo_mode:1; 19 - 20 - /* toggle chip select after every word */ 21 - unsigned cs_per_word:1; 22 19 }; 23 20 24 21 #endif