1. 程式人生 > >配置核心gpio模擬spi時序的方法

配置核心gpio模擬spi時序的方法

假如你現在有一份基於核心介面SPI的驅動,但是現在你的硬體已經沒有多餘的SPI介面了。怎麼辦?難道我們需要重新寫驅動嗎,像微控制器一樣去操作IO的高低來符合時序。那麼你的工作量就加大了。其實,linux核心已經寫好了模擬SPI時序,你只需要配置好。就可以使用了。下面分享一下個人經驗。

首先,你需要配置CONFIG。

config SPI_GPIO
tristate "GPIO-based bitbanging SPI Master"
depends on GENERIC_GPIO
select SPI_BITBANG

其次,你需要在你的平臺註冊platform_device,保證能讓spi-gpio.c能執行到probe函式。

static struct spi_gpio_platform_data xxx_data = {
	.sck = Pin(1),
	.mosi = Pin(2),
	.miso  = Pin(3),
	.num_chipselect = 1,
};
struct platform_device xxx_device = {
	.name		= DRIVER_NAME,
	.id             = 0,
	.dev = {
		.platform_data = &xxx_data,
	},
};
然後,你需要註冊spi_board_info結構體,並初始化。
static struct spi_board_info xxxxx_board_info[] __initdata = {
	{
		.modalias	= xxxx,
		.max_speed_hz	= 1200000,
		.bus_num	= 0,
		.chip_select	= 0,
		.mode		= SPI_MODE_x,
		.controller_data = (void *)Pin(4), 
	},
};

當你完成了以上步驟,恭喜你。模擬SPI已經配置成功了。接下來,你的硬體SPI驅動也可以相容模擬IO的了。

那麼核心是如何實現模擬SPI時序的呢?實現介面在spi-bitbang-txrx.h。

static inline u32
bitbang_txrx_be_cpha0(struct spi_device *spi,
		unsigned nsecs, unsigned cpol, unsigned flags,
		u32 word, u8 bits)
{
	/* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */

	/* clock starts at inactive polarity */
	for (word <<= (32 - bits); likely(bits); bits--) {

		/* setup MSB (to slave) on trailing edge */
		if ((flags & SPI_MASTER_NO_TX) == 0)
			setmosi(spi, word & (1 << 31));
		spidelay(nsecs);	/* T(setup) */

		setsck(spi, !cpol);
		spidelay(nsecs);

		/* sample MSB (from slave) on leading edge */
		word <<= 1;
		if ((flags & SPI_MASTER_NO_RX) == 0)
			word |= getmiso(spi);
		setsck(spi, cpol);
	}
	return word;
}

面是SPI模式0和模式2的介面時序實現方法。 仔細分析下,是不是和微控制器SPI模擬時序一樣。