* Girish. S. G. <girishsg@xxxxxx> [080730 14:55]: > PM related changes for McSPI This should be sent to spi-devel-general@xxxxxxxxxxxxxxxxxxxxx, please also Cc linux-omap list. Thanks, Tony > Signed-off-by: Girish S G <girishsg@xxxxxx> > --- > arch/arm/mach-omap2/devices.c | 26 ++++- > drivers/spi/omap2_mcspi.c | 195 ++++++++++++++++++++++++++++++++++++++---- > 2 files changed, 204 insertions(+), 17 deletions(-) > > Index: linux-omap-2.6/arch/arm/mach-omap2/devices.c > =================================================================== > --- linux-omap-2.6.orig/arch/arm/mach-omap2/devices.c 2008-07-30 > 16:49:21.000000000 +0530 > +++ linux-omap-2.6/arch/arm/mach-omap2/devices.c 2008-07-30 16:57:53.000000000 > +0530 > @@ -168,6 +168,11 @@ > .end = OMAP2_MCSPI1_BASE + 0xff, > .flags = IORESOURCE_MEM, > }, > + > + { > + .start = INT_24XX_SPI1_IRQ, > + .flags = IORESOURCE_IRQ, > + }, > }; > > static struct platform_device omap2_mcspi1 = { > @@ -190,6 +195,11 @@ > .end = OMAP2_MCSPI2_BASE + 0xff, > .flags = IORESOURCE_MEM, > }, > + > + { > + .start = INT_24XX_SPI2_IRQ, > + .flags = IORESOURCE_IRQ, > + }, > }; > > static struct platform_device omap2_mcspi2 = { > @@ -209,9 +219,14 @@ > > static struct resource omap2_mcspi3_resources[] = { > { > - .start = OMAP2_MCSPI3_BASE, > - .end = OMAP2_MCSPI3_BASE + 0xff, > - .flags = IORESOURCE_MEM, > + .start = OMAP2_MCSPI3_BASE, > + .end = OMAP2_MCSPI3_BASE + 0xff, > + .flags = IORESOURCE_MEM, > + }, > + > + { > + .start = INT_24XX_SPI3_IRQ, > + .flags = IORESOURCE_IRQ, > }, > }; > > @@ -237,6 +252,11 @@ > .end = OMAP2_MCSPI4_BASE + 0xff, > .flags = IORESOURCE_MEM, > }, > + > + { > + .start = INT_34XX_SPI4_IRQ, > + .flags = IORESOURCE_IRQ, > + }, > }; > > static struct platform_device omap2_mcspi4 = { > Index: linux-omap-2.6/drivers/spi/omap2_mcspi.c > =================================================================== > --- linux-omap-2.6.orig/drivers/spi/omap2_mcspi.c 2008-07-30 16:49:59.000000000 > +0530 > +++ linux-omap-2.6/drivers/spi/omap2_mcspi.c 2008-07-30 17:11:23.000000000 +0530 > @@ -35,6 +35,8 @@ > > #include <linux/spi/spi.h> > > +#include <asm/system.h> > +#include <asm/irq.h> > #include <asm/arch/dma.h> > #include <asm/arch/clock.h> > > @@ -61,8 +63,11 @@ > > #define OMAP2_MCSPI_SYSCONFIG_AUTOIDLE (1 << 0) > #define OMAP2_MCSPI_SYSCONFIG_SOFTRESET (1 << 1) > +#define OMAP2_AFTR_RST_SET_MASTER (0 << 2) > > #define OMAP2_MCSPI_SYSSTATUS_RESETDONE (1 << 0) > +#define OMAP2_MCSPI_SYS_CON_LVL_1 1 > +#define OMAP2_MCSPI_SYS_CON_LVL_2 2 > > #define OMAP2_MCSPI_MODULCTRL_SINGLE (1 << 0) > #define OMAP2_MCSPI_MODULCTRL_MS (1 << 2) > @@ -84,6 +89,11 @@ > #define OMAP2_MCSPI_CHCONF_TURBO (1 << 19) > #define OMAP2_MCSPI_CHCONF_FORCE (1 << 20) > > +#define OMAP2_MCSPI_SYSCFG_WKUP (1 << 2) > +#define OMAP2_MCSPI_SYSCFG_IDL (2 << 3) > +#define OMAP2_MCSPI_SYSCFG_CLK (2 << 8) > +#define OMAP2_MCSPI_WAKEUP_EN (1 << 1) > +#define OMAP2_MCSPI_IRQ_WKS (1 << 16) > #define OMAP2_MCSPI_CHSTAT_RXS (1 << 0) > #define OMAP2_MCSPI_CHSTAT_TXS (1 << 1) > #define OMAP2_MCSPI_CHSTAT_EOT (1 << 2) > @@ -128,6 +138,15 @@ > int word_len; > }; > > +#if defined(CONFIG_OMAP34XX_OFFMODE) && defined(CONFIG_OMAP3_PM) > +struct omap_mcspi_regs { > + u32 sysconfig; > + u32 modulctrl; > + u32 chconf0; > + u32 chconf1; > +}; > +static struct omap_mcspi_regs mcspi_ctx[4]; > +#endif /* #ifdef CONFIG_OMAP34XX_OFFMODE */ > static struct workqueue_struct *omap2_mcspi_wq; > > #define MOD_REG_BIT(val, mask, set) do { \ > @@ -152,6 +171,14 @@ > return __raw_readl(mcspi->base + idx); > } > > +static inline void mcspi_write_wkup_reg(struct spi_master *master, > + int idx, u32 val) > +{ > + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); > + > + __raw_writel(val, mcspi->base + idx); > +} > + > static inline void mcspi_write_cs_reg(const struct spi_device *spi, > int idx, u32 val) > { > @@ -214,6 +241,99 @@ > mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l); > } > > +static void omap_mcspi_wakeup_enable(struct spi_master *spi_cntrl, int level) > +{ > + if (level == OMAP2_MCSPI_SYS_CON_LVL_1) > + mcspi_write_wkup_reg(spi_cntrl, OMAP2_MCSPI_SYSCONFIG, > + (mcspi_read_reg(spi_cntrl, OMAP2_MCSPI_SYSCONFIG) | > + OMAP2_MCSPI_SYSCFG_WKUP | OMAP2_MCSPI_SYSCFG_IDL | > + OMAP2_MCSPI_SYSCFG_CLK | > + OMAP2_MCSPI_SYSCONFIG_AUTOIDLE)); > + > + if (level == OMAP2_MCSPI_SYS_CON_LVL_2) > + mcspi_write_wkup_reg(spi_cntrl, OMAP2_MCSPI_SYSCONFIG, > + (mcspi_read_reg(spi_cntrl, OMAP2_MCSPI_SYSCONFIG) | > + OMAP2_MCSPI_SYSCFG_WKUP | OMAP2_MCSPI_SYSCFG_IDL | > + OMAP2_MCSPI_SYSCONFIG_AUTOIDLE)); > + > + mcspi_write_wkup_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE, > + OMAP2_MCSPI_WAKEUP_EN); > + > + /* enable wakeup interrupt*/ > + mcspi_write_wkup_reg(spi_cntrl, OMAP2_MCSPI_IRQENABLE, > + (mcspi_read_reg(spi_cntrl, > + OMAP2_MCSPI_IRQENABLE) | OMAP2_MCSPI_IRQ_WKS)); > +} > + > +#if defined(CONFIG_OMAP34XX_OFFMODE) && defined(CONFIG_OMAP3_PM) > +static void omap2_mcspi_save_ctx(struct omap2_mcspi *mcspi) > +{ > + struct spi_master *spi_cntrl; > + spi_cntrl = mcspi->master; > + > + /* McSPI : context save */ > + mcspi_ctx[spi_cntrl->bus_num - 1].modulctrl = mcspi_read_reg(spi_cntrl, > + OMAP2_MCSPI_MODULCTRL); > + mcspi_ctx[spi_cntrl->bus_num - 1].sysconfig = mcspi_read_reg(spi_cntrl, > + OMAP2_MCSPI_SYSCONFIG); > + > + mcspi_ctx[spi_cntrl->bus_num - 1].chconf0 = mcspi_read_reg(spi_cntrl, > + OMAP2_MCSPI_CHCONF0); > + if (spi_cntrl->bus_num != 4) > + mcspi_ctx[spi_cntrl->bus_num - 1].chconf1 = > + mcspi_read_reg(spi_cntrl, OMAP2_MCSPI_CHCONF0 + 0x14); > +} > + > +static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) > +{ > + struct spi_master *spi_cntrl; > + spi_cntrl = mcspi->master; > + > + /*McSPI : context restore */ > + mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_MODULCTRL, > + mcspi_ctx[spi_cntrl->bus_num - 1].modulctrl); > + mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_SYSCONFIG, > + mcspi_ctx[spi_cntrl->bus_num - 1].sysconfig); > + > + mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_CHCONF0, > + mcspi_ctx[spi_cntrl->bus_num - 1].chconf0); > + if (spi_cntrl->bus_num != 4) > + mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_CHCONF0 + 0x14, > + mcspi_ctx[spi_cntrl->bus_num - 1].chconf1); > +} > + > +#endif /* #ifdef CONFIG_OMAP34XX_OFFMODE */ > + > +static int omap_mcspi_enable_clocks(struct omap2_mcspi *mcspi) > + > +{ > + struct spi_master *spi_cntrl = mcspi->master; > + if (clk_enable(mcspi->ick)) > + return -ENODEV; > + if (clk_enable(mcspi->fck)) { > + clk_disable(mcspi->ick); > + return -ENODEV; > + } > +#if defined(CONFIG_OMAP34XX_OFFMODE) && defined(CONFIG_OMAP3_PM) > + if (context_restore_required(mcspi->fck)) > + omap2_mcspi_restore_ctx(mcspi); > +#endif /* #ifdef CONFIG_OMAP34XX_OFFMODE */ > + omap_mcspi_wakeup_enable(spi_cntrl, OMAP2_MCSPI_SYS_CON_LVL_1); > + return 0; > +} > + > +static void omap_mcspi_disable_clocks(struct omap2_mcspi *mcspi) > + > +{ > + struct spi_master *spi_cntrl = mcspi->master; > + omap_mcspi_wakeup_enable(spi_cntrl, OMAP2_MCSPI_SYS_CON_LVL_2); > +#if defined(CONFIG_OMAP34XX_OFFMODE) && defined(CONFIG_OMAP3_PM) > + omap2_mcspi_save_ctx(mcspi); > +#endif /* #ifdef CONFIG_OMAP34XX_OFFMODE */ > + clk_disable(mcspi->ick); > + clk_disable(mcspi->fck); > +} > + > static unsigned > omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) > { > @@ -475,6 +595,29 @@ > return count - c; > } > > +static irqreturn_t > +omap_mcspi_isr(int irq, void *mcspi_id) > +{ > + struct omap2_mcspi *mcspi = mcspi_id; > + u32 flags; > + u32 irqstatus = 0; > + > + omap_mcspi_enable_clocks(mcspi); > + > + irqstatus = mcspi_read_reg((struct spi_master *)mcspi->master, > + OMAP2_MCSPI_IRQSTATUS); > + if (irqstatus & OMAP2_MCSPI_IRQ_WKS) { > + spin_lock_irqsave(&mcspi->lock, flags); > + > + /* clear the wakeup interrupt */ > + mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS, > + OMAP2_MCSPI_IRQ_WKS); > + spin_unlock_irqrestore(&mcspi->lock, flags); > + } > + omap_mcspi_disable_clocks(mcspi); > + > + return IRQ_HANDLED; > +} > /* called only when no transfer is active to this device */ > static int omap2_mcspi_setup_transfer(struct spi_device *spi, > struct spi_transfer *t) > @@ -643,11 +786,12 @@ > return ret; > } > > - clk_enable(mcspi->ick); > - clk_enable(mcspi->fck); > + if (omap_mcspi_enable_clocks(mcspi)) { > + dev_dbg(&spi->dev, "Unable to get SPI clocks"); > + return -ENODEV; > + } > ret = omap2_mcspi_setup_transfer(spi, NULL); > - clk_disable(mcspi->fck); > - clk_disable(mcspi->ick); > + omap_mcspi_disable_clocks(mcspi); > > return ret; > } > @@ -679,8 +823,7 @@ > mcspi = container_of(work, struct omap2_mcspi, work); > spin_lock_irq(&mcspi->lock); > > - clk_enable(mcspi->ick); > - clk_enable(mcspi->fck); > + omap_mcspi_enable_clocks(mcspi); > > /* We only enable one channel at a time -- the one whose message is > * at the head of the queue -- although this controller would gladly > @@ -871,8 +1014,8 @@ > struct spi_master *master = mcspi->master; > u32 tmp; > > - clk_enable(mcspi->ick); > - clk_enable(mcspi->fck); > + if (omap_mcspi_enable_clocks(mcspi)) > + return -ENODEV; > > mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG, > OMAP2_MCSPI_SYSCONFIG_SOFTRESET); > @@ -880,14 +1023,12 @@ > tmp = mcspi_read_reg(master, OMAP2_MCSPI_SYSSTATUS); > } while (!(tmp & OMAP2_MCSPI_SYSSTATUS_RESETDONE)); > > - mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG, > - /* (3 << 8) | (2 << 3) | */ > - OMAP2_MCSPI_SYSCONFIG_AUTOIDLE); > + /* call wakeup function to set sysconfig as per pm activity*/ > + omap_mcspi_wakeup_enable(master, OMAP2_MCSPI_SYS_CON_LVL_1); > > omap2_mcspi_set_master_mode(master); > > - clk_disable(mcspi->fck); > - clk_disable(mcspi->ick); > + omap_mcspi_disable_clocks(mcspi); > return 0; > } > > @@ -941,7 +1082,7 @@ > { > struct spi_master *master; > struct omap2_mcspi *mcspi; > - struct resource *r; > + struct resource *r, *r_irq; > int status = 0, i; > const u8 *rxdma_id, *txdma_id; > unsigned num_chipselect; > @@ -1025,6 +1166,19 @@ > goto err2; > } > > + r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); > + if (r_irq == NULL) { > + status = -ENODEV; > + goto err1; > + } > + > + /* request irq for the channel*/ > + if (request_irq(r_irq->start, omap_mcspi_isr, > + IRQF_DISABLED | IRQF_SAMPLE_RANDOM, > + "omap_mcspi_isr", mcspi)) { > + printk(KERN_ERR "MCSPI ERROR: couldnt allocate irq\n"); > + } > + > mcspi->dma_channels = kcalloc(master->num_chipselect, > sizeof(struct omap2_mcspi_dma), > GFP_KERNEL); > @@ -1061,6 +1215,17 @@ > return status; > } > > +static int __devexit omap2_mcspi_suspend(struct platform_device *pdev, > + pm_message_t state) > +{ > + /* do nothing as of now */ > + return 0; > +} > +static int __devexit omap2_mcspi_resume(struct platform_device *pdev) > +{ > + /* do nothing as of now: agressive power managment */ > + return 0; > +} > static int __exit omap2_mcspi_remove(struct platform_device *pdev) > { > struct spi_master *master; > @@ -1092,6 +1257,8 @@ > .name = "omap2_mcspi", > .owner = THIS_MODULE, > }, > + .suspend = omap2_mcspi_suspend, > + .resume = omap2_mcspi_resume, > .remove = __exit_p(omap2_mcspi_remove), > }; > -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html