I want to use the mcspi0 as spi slave. As it is not currently supported in kernel, I modified the omap2_mcspi.c to support slave mode
I need to enable the SPI interrupts RX receive of data.
when I enable the interrupts OMAP2_MCSPI_IRQENABLE_RX0_FULL and OMAP2_MCSPI_IRQENABLE_RX0_OVERFLOW
I found that I am not getting any interrupts but the whole system hangs after 30 sec.
But if OMAP2_MCSPI_IRQENABLE_RX0_FULL enable bit is not set I am not facing any hang up issues. Is interrupt modes already tested in kernel.
Following configuration are done for enabling the module and configure it as slave
int omap2_mcspi_setup_transfer(struct spi_slave_device *spi )
{
struct omap2_mcspi *mcspi = g_mcspi;
u8 word_len = spi->bits_per_word;
u32 reg_val;
_SPI_DBG(" ");
mcspi->char_len = spi->bits_per_word;
omap2_mcspi_set_enable(mcspi, 0);
reg_val = mcspi_read_reg(mcspi, OMAP2_MCSPI_CHCONF0);
/* set SPI mode 0..3 */
if (spi->mode & SPI_CPOL)
reg_val |= OMAP2_MCSPI_CHCONF_POL;
else
reg_val &= ~OMAP2_MCSPI_CHCONF_POL;
if (spi->mode & SPI_CPHA)
reg_val |= OMAP2_MCSPI_CHCONF_PHA;
else
reg_val &= ~OMAP2_MCSPI_CHCONF_PHA;
/* set chipselect polarity; manage with FORCE */
if (!(spi->mode & SPI_CS_HIGH))
reg_val |= OMAP2_MCSPI_CHCONF_EPOL; /* active-low; normal */
else
reg_val &= ~OMAP2_MCSPI_CHCONF_EPOL;
/* wordlength */
reg_val &= ~OMAP2_MCSPI_CHCONF_WL_MASK;
reg_val |= (word_len - 1) << 7;
/* SPIDAT[0] for RX and SPIDAT[1] for TX */
reg_val &= ~(OMAP2_MCSPI_CHCONF_IS|OMAP2_MCSPI_CHCONF_DPE1);
reg_val |= OMAP2_MCSPI_CHCONF_DPE0;
mcspi_write_reg(mcspi, OMAP2_MCSPI_CHCONF0, reg_val);
omap2_mcspi_set_enable(mcspi, OMAP2_MCSPI_CHCTRL_EN);
_SPI_DBG("enable RX interrupt");
/* enable RX interrupt */
mcspi_write_reg(mcspi, OMAP2_MCSPI_IRQENABLE, (OMAP2_MCSPI_IRQENABLE_RX0_FULL|OMAP2_MCSPI_IRQENABLE_RX0_OVERFLOW ));
//OMAP2_MCSPI_IRQENABLE_RX0_FULL
return 0;
}
probe function
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (r == NULL) {
status = -ENODEV;
goto err1;
}
if (!request_mem_region(r->start, (r->end - r->start) + 1,
dev_name(&pdev->dev))) {
status = -EBUSY;
goto err1;
}
g_mcspi->phys = r->start;
g_mcspi->base = ioremap(r->start, r->end - r->start + 1);
if (!g_mcspi->base) {
dev_dbg(&pdev->dev, "can't ioremap MCSPI\n");
status = -ENOMEM;
goto err1aa;
}
/* intialize share lock */
spin_lock_init(&g_mcspi->rx_fifo_lock);
error = kfifo_alloc(&g_mcspi->rx_fifo, 512, GFP_KERNEL);
if (error) {
printk(KERN_ERR "g_mcspi->rx_fifo failed\n");
goto err1a;
}
init_completion(&g_mcspi->rx_completion);
g_mcspi->ick = clk_get(&pdev->dev, "ick");
if (IS_ERR(g_mcspi->ick)) {
printk(KERN_ERR "can't get mcspi_ick\n");
status = PTR_ERR(g_mcspi->ick);
goto err1a;
}
g_mcspi->fck = clk_get(&pdev->dev, "fck");
if (IS_ERR(g_mcspi->fck)) {
printk(KERN_ERR "can't get mcspi_fck\n");
status = PTR_ERR(g_mcspi->fck);
goto err2;
}
g_mcspi->irq = platform_get_irq(pdev, 0);
_SPI_DBG( "g_mcspi->irq = 0x%x in %s ", g_mcspi->irq, pdev->name );
if (g_mcspi->irq <= 0) {
status = -EINVAL;
goto err1a;
}
/* request irq for SPI */
rc = request_irq(g_mcspi->irq, omap2_spi_isr, 0, pdev->name, g_mcspi);
if (rc != 0)
{
printk(KERN_ERR "request IRQ 0x%x in %s failed with rc %d", g_mcspi->irq, pdev->name, rc);
status = rc;
goto err1a;
}
_SPI_DBG( "request irq for SPI done " );
if (omap2_mcspi_reset(g_mcspi) < 0)
{
printk(KERN_ERR "failed omap2_mcspi_reset ");
goto err4;
}
static void omap2_mcspi_set_slave_mode(struct omap2_mcspi *mcspi)
{
u32 l;
/* setup for slave mode
* only singe channel is supported in slave mode
*/
l = mcspi_read_reg(mcspi, OMAP2_MCSPI_MODULCTRL);
MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_STEST, 0);
MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_MS, 1);
MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, 1);
mcspi_write_reg(mcspi, OMAP2_MCSPI_MODULCTRL, l);
}
static int __init omap2_mcspi_reset(struct omap2_mcspi *mcspi)
{
u32 tmp;
if (omap2_mcspi_enable_clocks(mcspi))
return -1;
mcspi_write_reg(mcspi, OMAP2_MCSPI_SYSCONFIG,
OMAP2_MCSPI_SYSCONFIG_SOFTRESET);
do {
tmp = mcspi_read_reg(mcspi, OMAP2_MCSPI_SYSSTATUS);
} while (!(tmp & OMAP2_MCSPI_SYSSTATUS_RESETDONE));
tmp = OMAP2_MCSPI_SYSCONFIG_AUTOIDLE |
OMAP2_MCSPI_SYSCONFIG_SMARTIDLE;
mcspi_write_reg(mcspi, OMAP2_MCSPI_SYSCONFIG, tmp);
omap2_mcspi_set_slave_mode(mcspi);
/* clock remain enabled
omap2_mcspi_disable_clocks(mcspi);*/
return 0;
when I enable the interrupts OMAP2_MCSPI_IRQENABLE_RX0_FULL and OMAP2_MCSPI_IRQENABLE_RX0_OVERFLOW
I found that I am not getting any interrupts but the whole system hangs after 30 sec.
But if OMAP2_MCSPI_IRQENABLE_RX0_FULL enable bit is not set I am not facing any hang up issues.