On Fri, Aug 13, 2010 at 8:05 AM, Charulatha V <charu@xxxxxx> wrote: > From: Govindraj.R <govindraj.raja@xxxxxx> > > This patch converts the McSPI driver to use pm_runtime apis while > implementing it in HWMOD FW way. Hi Govindraj, Some comments below. Short version is that this patch seems to lump a number of (mostly) unrelated changes (the register map, HWMOD stuff, and runtime pm) that makes it hard to review and understand. I could use some help understanding what the intent of the patch is, and it would also help to split it up. Cheers, g. > > Signed-off-by: Charulatha V <charu@xxxxxx> > Signed-off-by: Partha Basak <p-basak2@xxxxxx> > Signed-off-by: Govindraj.R <govindraj.raja@xxxxxx> > --- > arch/arm/mach-omap2/clock3xxx_data.c | 4 + > arch/arm/mach-omap2/devices.c | 233 ++++++++++----------------- > arch/arm/plat-omap/include/plat/mcspi.h | 27 +++ > drivers/spi/omap2_mcspi.c | 273 ++++++++++--------------------- > 4 files changed, 204 insertions(+), 333 deletions(-) > > diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c > index 138646d..9482e4d 100644 > --- a/arch/arm/mach-omap2/clock3xxx_data.c > +++ b/arch/arm/mach-omap2/clock3xxx_data.c > @@ -1558,6 +1558,7 @@ static struct clk mcspi4_fck = { > .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), > .enable_bit = OMAP3430_EN_MCSPI4_SHIFT, > .recalc = &followparent_recalc, > + .clkdm_name = "core_l4_clkdm", > }; > > static struct clk mcspi3_fck = { > @@ -1567,6 +1568,7 @@ static struct clk mcspi3_fck = { > .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), > .enable_bit = OMAP3430_EN_MCSPI3_SHIFT, > .recalc = &followparent_recalc, > + .clkdm_name = "core_l4_clkdm", > }; > > static struct clk mcspi2_fck = { > @@ -1576,6 +1578,7 @@ static struct clk mcspi2_fck = { > .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), > .enable_bit = OMAP3430_EN_MCSPI2_SHIFT, > .recalc = &followparent_recalc, > + .clkdm_name = "core_l4_clkdm", > }; > > static struct clk mcspi1_fck = { > @@ -1585,6 +1588,7 @@ static struct clk mcspi1_fck = { > .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), > .enable_bit = OMAP3430_EN_MCSPI1_SHIFT, > .recalc = &followparent_recalc, > + .clkdm_name = "core_l4_clkdm", > }; > > static struct clk uart2_fck = { > diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c > index fa99da1..a869c35 100644 > --- a/arch/arm/mach-omap2/devices.c > +++ b/arch/arm/mach-omap2/devices.c > @@ -15,6 +15,8 @@ > #include <linux/platform_device.h> > #include <linux/io.h> > #include <linux/clk.h> > +#include <linux/err.h> > +#include <linux/slab.h> > > #include <mach/hardware.h> > #include <mach/irqs.h> > @@ -239,170 +241,103 @@ static inline void omap_init_sti(void) {} > > #include <plat/mcspi.h> > > -#define OMAP2_MCSPI1_BASE 0x48098000 > -#define OMAP2_MCSPI2_BASE 0x4809a000 > -#define OMAP2_MCSPI3_BASE 0x480b8000 > -#define OMAP2_MCSPI4_BASE 0x480ba000 > - > -#define OMAP4_MCSPI1_BASE 0x48098100 > -#define OMAP4_MCSPI2_BASE 0x4809a100 > -#define OMAP4_MCSPI3_BASE 0x480b8100 > -#define OMAP4_MCSPI4_BASE 0x480ba100 > - > -static struct omap2_mcspi_platform_config omap2_mcspi1_config = { > - .num_cs = 4, > - .force_cs_mode = 1, > -}; > - > -static struct resource omap2_mcspi1_resources[] = { > - { > - .start = OMAP2_MCSPI1_BASE, > - .end = OMAP2_MCSPI1_BASE + 0xff, > - .flags = IORESOURCE_MEM, > - }, > -}; > - > -static struct platform_device omap2_mcspi1 = { > - .name = "omap2_mcspi", > - .id = 1, > - .num_resources = ARRAY_SIZE(omap2_mcspi1_resources), > - .resource = omap2_mcspi1_resources, > - .dev = { > - .platform_data = &omap2_mcspi1_config, > - }, > -}; > - > -static struct omap2_mcspi_platform_config omap2_mcspi2_config = { > - .num_cs = 2, > - .mode = OMAP2_MCSPI_MASTER, > - .dma_mode = 0, > - .force_cs_mode = 0, > - .fifo_depth = 0, > -}; > - > -static struct resource omap2_mcspi2_resources[] = { > - { > - .start = OMAP2_MCSPI2_BASE, > - .end = OMAP2_MCSPI2_BASE + 0xff, > - .flags = IORESOURCE_MEM, > - }, > -}; > - > -static struct platform_device omap2_mcspi2 = { > - .name = "omap2_mcspi", > - .id = 2, > - .num_resources = ARRAY_SIZE(omap2_mcspi2_resources), > - .resource = omap2_mcspi2_resources, > - .dev = { > - .platform_data = &omap2_mcspi2_config, > - }, > -}; > - > -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \ > - defined(CONFIG_ARCH_OMAP4) > -static struct omap2_mcspi_platform_config omap2_mcspi3_config = { > - .num_cs = 2, > -}; > - > -static struct resource omap2_mcspi3_resources[] = { > - { > - .start = OMAP2_MCSPI3_BASE, > - .end = OMAP2_MCSPI3_BASE + 0xff, > - .flags = IORESOURCE_MEM, > - }, > -}; > - > -static struct platform_device omap2_mcspi3 = { > - .name = "omap2_mcspi", > - .id = 3, > - .num_resources = ARRAY_SIZE(omap2_mcspi3_resources), > - .resource = omap2_mcspi3_resources, > - .dev = { > - .platform_data = &omap2_mcspi3_config, > - }, > -}; > -#endif > - > -#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) > -static struct omap2_mcspi_platform_config omap2_mcspi4_config = { > - .num_cs = 1, > -}; > - > -static struct resource omap2_mcspi4_resources[] = { > - { > - .start = OMAP2_MCSPI4_BASE, > - .end = OMAP2_MCSPI4_BASE + 0xff, > - .flags = IORESOURCE_MEM, > - }, > -}; > - > -static struct platform_device omap2_mcspi4 = { > - .name = "omap2_mcspi", > - .id = 4, > - .num_resources = ARRAY_SIZE(omap2_mcspi4_resources), > - .resource = omap2_mcspi4_resources, > - .dev = { > - .platform_data = &omap2_mcspi4_config, > - }, > -}; > -#endif > - > -#ifdef CONFIG_ARCH_OMAP4 > -static inline void omap4_mcspi_fixup(void) > +struct omap_device_pm_latency omap_mcspi_latency[] = { > + [0] = { > + .deactivate_func = omap_device_idle_hwmods, > + .activate_func = omap_device_enable_hwmods, > + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST, > + }, > +}; > + > +static const u16 omap2_reg_map[] = { > + [OMAP2_MCSPI_REVISION] = 0x00, > + [OMAP2_MCSPI_SYSCONFIG] = 0x10, > + [OMAP2_MCSPI_SYSSTATUS] = 0x14, > + [OMAP2_MCSPI_IRQSTATUS] = 0x18, > + [OMAP2_MCSPI_IRQENABLE] = 0x1c, > + [OMAP2_MCSPI_WAKEUPENABLE] = 0x20, > + [OMAP2_MCSPI_SYST] = 0x24, > + [OMAP2_MCSPI_MODULCTRL] = 0x28, > + [OMAP2_MCSPI_XFERLEVEL] = 0x7c, > + [OMAP2_MCSPI_CHCONF0] = 0x2c, > + [OMAP2_MCSPI_CHSTAT0] = 0x30, > + [OMAP2_MCSPI_CHCTRL0] = 0x34, > + [OMAP2_MCSPI_TX0] = 0x38, > + [OMAP2_MCSPI_RX0] = 0x3c, > +}; > + > +static const u16 omap4_reg_map[] = { > + [OMAP2_MCSPI_REVISION] = 0x100, > + [OMAP2_MCSPI_SYSCONFIG] = 0x110, > + [OMAP2_MCSPI_SYSSTATUS] = 0x114, > + [OMAP2_MCSPI_IRQSTATUS] = 0x118, > + [OMAP2_MCSPI_IRQENABLE] = 0x01c, > + [OMAP2_MCSPI_WAKEUPENABLE] = 0x120, > + [OMAP2_MCSPI_SYST] = 0x124, > + [OMAP2_MCSPI_MODULCTRL] = 0x128, > + [OMAP2_MCSPI_XFERLEVEL] = 0x17c, > + [OMAP2_MCSPI_CHCONF0] = 0x12c, > + [OMAP2_MCSPI_CHSTAT0] = 0x130, > + [OMAP2_MCSPI_CHCTRL0] = 0x134, > + [OMAP2_MCSPI_TX0] = 0x138, > + [OMAP2_MCSPI_RX0] = 0x13c, > + [OMAP2_MCSPI_HL_REV] = 0x000, > + [OMAP2_MCSPI_HL_HWINFO] = 0x004, > + [OMAP2_MCSPI_HL_SYSCONFIG] = 0x010, > +}; Other than an 0x100 offset for omap4 and the addition of revision registers, these two register maps are identical. Is it really worth having a complete register map table for two things that aren't really different? It looks overengineered. Personally I'd handle this by having two base address pointers; the regs pointer and the info/revision pointer. omap4 would have the revision base set, and omap2 would not. > + > +static int omap_mcspi_init(struct omap_hwmod *oh, void *user) > { > - omap2_mcspi1_resources[0].start = OMAP4_MCSPI1_BASE; > - omap2_mcspi1_resources[0].end = OMAP4_MCSPI1_BASE + 0xff; > - omap2_mcspi2_resources[0].start = OMAP4_MCSPI2_BASE; > - omap2_mcspi2_resources[0].end = OMAP4_MCSPI2_BASE + 0xff; > - omap2_mcspi3_resources[0].start = OMAP4_MCSPI3_BASE; > - omap2_mcspi3_resources[0].end = OMAP4_MCSPI3_BASE + 0xff; > - omap2_mcspi4_resources[0].start = OMAP4_MCSPI4_BASE; > - omap2_mcspi4_resources[0].end = OMAP4_MCSPI4_BASE + 0xff; > -} > -#else > -static inline void omap4_mcspi_fixup(void) > -{ > -} > -#endif > + struct omap_device *od; > + char *name = "omap2_mcspi"; > + struct omap2_mcspi_platform_config *pdata; > + static int spi_num; > + > + pdata = kzalloc(sizeof(struct omap2_mcspi_platform_config), > + GFP_KERNEL); > + if (!pdata) { > + pr_err("\nMemory allocation for Mcspi device failed\n"); > + return -ENOMEM; > + } > > -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \ > - defined(CONFIG_ARCH_OMAP4) > -static inline void omap2_mcspi3_init(void) > -{ > - platform_device_register(&omap2_mcspi3); > -} > -#else > -static inline void omap2_mcspi3_init(void) > -{ > -} > -#endif > + switch (spi_num) { > + case 0: > + pdata->num_cs = 4; > + pdata->force_cs_mode = 1; > + break; > + case 1: > + pdata->num_cs = 2; > + pdata->mode = OMAP2_MCSPI_MASTER; > + pdata->dma_mode = 1; > + pdata->force_cs_mode = 0; > + pdata->fifo_depth = 0; > + break; > + case 2: > + pdata->num_cs = 2; > + break; > + case 3: > + pdata->num_cs = 1; > + break; > + } HWMOD appears to have the purpose of making device instantiation data driven. If so, shouldn't these parameters also be extracted from the HWMOD data? > -#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) > -static inline void omap2_mcspi4_init(void) > -{ > - platform_device_register(&omap2_mcspi4); > -} > -#else > -static inline void omap2_mcspi4_init(void) > -{ > + if (cpu_is_omap44xx()) > + pdata->regs_data = (u16 *)omap4_reg_map; > + else > + pdata->regs_data = (u16 *)omap2_reg_map; > + > + od = omap_device_build(name, spi_num + 1, oh, pdata, > + sizeof(*pdata), omap_mcspi_latency, > + ARRAY_SIZE(omap_mcspi_latency), 0); > + WARN(IS_ERR(od), "\nCant build omap_device for %s:%s\n", > + name, oh->name); > + spi_num++; > + return 0; > } > -#endif > > static void omap_init_mcspi(void) > { > - if (cpu_is_omap44xx()) > - omap4_mcspi_fixup(); > - > - platform_device_register(&omap2_mcspi1); > - platform_device_register(&omap2_mcspi2); > - > - if (cpu_is_omap2430() || cpu_is_omap343x() || cpu_is_omap44xx()) > - omap2_mcspi3_init(); > - > - if (cpu_is_omap343x() || cpu_is_omap44xx()) > - omap2_mcspi4_init(); > + omap_hwmod_for_each_by_class("mcspi", omap_mcspi_init, NULL); > } > - > #else > static inline void omap_init_mcspi(void) {} > #endif > diff --git a/arch/arm/plat-omap/include/plat/mcspi.h b/arch/arm/plat-omap/include/plat/mcspi.h > index 23b928b..27161be 100644 > --- a/arch/arm/plat-omap/include/plat/mcspi.h > +++ b/arch/arm/plat-omap/include/plat/mcspi.h > @@ -1,6 +1,10 @@ > #ifndef _OMAP2_MCSPI_H > #define _OMAP2_MCSPI_H > > +#if defined CONFIG_ARCH_OMAP2PLUS > +#include <plat/omap_hwmod.h> > +#include <plat/omap_device.h> > + > #define OMAP2_MCSPI_MASTER 0 > #define OMAP2_MCSPI_SLAVE 1 > > @@ -30,6 +34,7 @@ struct omap2_mcspi_platform_config { > u8 dma_mode; > u8 force_cs_mode; > unsigned short fifo_depth; > + u16 *regs_data; > }; > > struct omap2_mcspi_device_config { > @@ -39,4 +44,26 @@ struct omap2_mcspi_device_config { > unsigned single_channel:1; > }; > > +enum { > + OMAP2_MCSPI_REVISION = 0, > + OMAP2_MCSPI_SYSCONFIG, > + OMAP2_MCSPI_SYSSTATUS, > + OMAP2_MCSPI_IRQSTATUS, > + OMAP2_MCSPI_IRQENABLE, > + OMAP2_MCSPI_WAKEUPENABLE, > + OMAP2_MCSPI_SYST, > + OMAP2_MCSPI_MODULCTRL, > + OMAP2_MCSPI_XFERLEVEL, > + OMAP2_MCSPI_CHCONF0, > + OMAP2_MCSPI_CHSTAT0, > + OMAP2_MCSPI_CHCTRL0, > + OMAP2_MCSPI_TX0, > + OMAP2_MCSPI_RX0, > + OMAP2_MCSPI_HL_REV, > + OMAP2_MCSPI_HL_HWINFO, > + OMAP2_MCSPI_HL_SYSCONFIG, > +}; > + > +#endif > + > #endif > diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c > index 0c9d1be..44a8bb0 100644 > --- a/drivers/spi/omap2_mcspi.c > +++ b/drivers/spi/omap2_mcspi.c > @@ -33,6 +33,7 @@ > #include <linux/clk.h> > #include <linux/io.h> > #include <linux/slab.h> > +#include <linux/pm_runtime.h> > > #include <linux/spi/spi.h> > > @@ -43,35 +44,11 @@ > #define OMAP2_MCSPI_MAX_FREQ 48000000 > #define OMAP2_MCSPI_MAX_FIFODEPTH 64 > > -/* OMAP2 has 3 SPI controllers, while OMAP3 has 4 */ > +/* OMAP2 has 3 SPI controllers, while OMAP3/4 has 4 */ > #define OMAP2_MCSPI_MAX_CTRL 4 > > -#define OMAP2_MCSPI_REVISION 0x00 > -#define OMAP2_MCSPI_SYSCONFIG 0x10 > -#define OMAP2_MCSPI_SYSSTATUS 0x14 > -#define OMAP2_MCSPI_IRQSTATUS 0x18 > -#define OMAP2_MCSPI_IRQENABLE 0x1c > -#define OMAP2_MCSPI_WAKEUPENABLE 0x20 > -#define OMAP2_MCSPI_SYST 0x24 > -#define OMAP2_MCSPI_MODULCTRL 0x28 > -#define OMAP2_MCSPI_XFERLEVEL 0x7c > - > -/* per-channel banks, 0x14 bytes each, first is: */ > -#define OMAP2_MCSPI_CHCONF0 0x2c > -#define OMAP2_MCSPI_CHSTAT0 0x30 > -#define OMAP2_MCSPI_CHCTRL0 0x34 > -#define OMAP2_MCSPI_TX0 0x38 > -#define OMAP2_MCSPI_RX0 0x3c > - > /* per-register bitmasks: */ > > -#define OMAP2_MCSPI_SYSCONFIG_SMARTIDLE BIT(4) > -#define OMAP2_MCSPI_SYSCONFIG_ENAWAKEUP BIT(2) > -#define OMAP2_MCSPI_SYSCONFIG_AUTOIDLE BIT(0) > -#define OMAP2_MCSPI_SYSCONFIG_SOFTRESET BIT(1) > - > -#define OMAP2_MCSPI_SYSSTATUS_RESETDONE BIT(0) > - > #define OMAP2_MCSPI_MODULCTRL_SINGLE BIT(0) > #define OMAP2_MCSPI_MODULCTRL_MS BIT(2) > #define OMAP2_MCSPI_MODULCTRL_STEST BIT(3) > @@ -127,10 +104,9 @@ struct omap2_mcspi { > spinlock_t lock; > struct list_head msg_queue; > struct spi_master *master; > - struct clk *ick; > - struct clk *fck; > /* Virtual base address of the controller */ > void __iomem *base; > + u16 *regs; would void __iomem * be more appropriate for regs? I imagine regs should never be dereferenced directly. > unsigned long phys; > /* SPI1 has 4 channels, while SPI2 has 2 */ > struct omap2_mcspi_dma *dma_channels; > @@ -138,6 +114,7 @@ struct omap2_mcspi { > u8 dma_mode; > u8 force_cs_mode; > u16 fifo_depth; > + struct device *dev; > }; > > struct omap2_mcspi_cs { > @@ -153,7 +130,6 @@ struct omap2_mcspi_cs { > * corresponding registers are modified. > */ > struct omap2_mcspi_regs { > - u32 sysconfig; > u32 modulctrl; > u32 wakeupenable; > struct list_head cs; > @@ -206,29 +182,33 @@ static inline void mcspi_write_reg(struct spi_master *master, > { > struct omap2_mcspi *mcspi = spi_master_get_devdata(master); > > - __raw_writel(val, mcspi->base + idx); > + __raw_writel(val, mcspi->base + mcspi->regs[idx]); > } > > static inline u32 mcspi_read_reg(struct spi_master *master, int idx) > { > struct omap2_mcspi *mcspi = spi_master_get_devdata(master); > > - return __raw_readl(mcspi->base + idx); > + return __raw_readl(mcspi->base + mcspi->regs[idx]); > } > > static inline void mcspi_write_cs_reg(const struct spi_device *spi, > int idx, u32 val) > { > struct omap2_mcspi_cs *cs = spi->controller_state; > + struct spi_master *master = spi->master; > + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); > > - __raw_writel(val, cs->base + idx); > + __raw_writel(val, cs->base + mcspi->regs[idx]); > } > > static inline u32 mcspi_read_cs_reg(const struct spi_device *spi, int idx) > { > struct omap2_mcspi_cs *cs = spi->controller_state; > + struct spi_master *master = spi->master; > + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); > > - return __raw_readl(cs->base + idx); > + return __raw_readl(cs->base + mcspi->regs[idx]); > } > > static inline u32 mcspi_cached_chconf0(const struct spi_device *spi) > @@ -454,32 +434,23 @@ static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) > mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_MODULCTRL, > omap2_mcspi_ctx[spi_cntrl->bus_num - 1].modulctrl); > > - mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_SYSCONFIG, > - omap2_mcspi_ctx[spi_cntrl->bus_num - 1].sysconfig); > - > mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE, > omap2_mcspi_ctx[spi_cntrl->bus_num - 1].wakeupenable); > > list_for_each_entry(cs, &omap2_mcspi_ctx[spi_cntrl->bus_num - 1].cs, > node) > - __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); > + __raw_writel(cs->chconf0, cs->base + > + mcspi->regs[OMAP2_MCSPI_CHCONF0]); > } > -static void omap2_mcspi_disable_clocks(struct omap2_mcspi *mcspi) > + > +static inline void omap2_mcspi_disable_clocks(struct omap2_mcspi *mcspi) > { > - clk_disable(mcspi->ick); > - clk_disable(mcspi->fck); > + pm_runtime_put_sync(mcspi->dev); > } > > -static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi) > +static inline int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi) > { > - if (clk_enable(mcspi->ick)) > - return -ENODEV; > - if (clk_enable(mcspi->fck)) > - return -ENODEV; > - > - omap2_mcspi_restore_ctx(mcspi); > - > - return 0; > + return pm_runtime_get_sync(mcspi->dev); > } > > static unsigned > @@ -499,7 +470,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) > > mcspi = spi_master_get_devdata(spi->master); > mcspi_dma = &mcspi->dma_channels[spi->chip_select]; > - irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS; > + irqstat_reg = mcspi->base + mcspi->regs[OMAP2_MCSPI_IRQSTATUS]; > l = mcspi_cached_chconf0(spi); > > count = xfer->len; > @@ -507,8 +478,8 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) > word_len = cs->word_len; > > base = cs->phys; > - tx_reg = base + OMAP2_MCSPI_TX0; > - rx_reg = base + OMAP2_MCSPI_RX0; > + tx_reg = base + mcspi->regs[OMAP2_MCSPI_TX0]; > + rx_reg = base + mcspi->regs[OMAP2_MCSPI_RX0]; > rx = xfer->rx_buf; > tx = xfer->tx_buf; > > @@ -692,9 +663,9 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) > > /* We store the pre-calculated register addresses on stack to speed > * up the transfer loop. */ > - tx_reg = base + OMAP2_MCSPI_TX0; > - rx_reg = base + OMAP2_MCSPI_RX0; > - chstat_reg = base + OMAP2_MCSPI_CHSTAT0; > + tx_reg = base + mcspi->regs[OMAP2_MCSPI_TX0]; > + rx_reg = base + mcspi->regs[OMAP2_MCSPI_RX0]; > + chstat_reg = base + mcspi->regs[OMAP2_MCSPI_CHSTAT0]; > > if (word_len <= 8) { > u8 *rx; > @@ -1047,7 +1018,7 @@ static int omap2_mcspi_setup(struct spi_device *spi) > return ret; > } > > - if (omap2_mcspi_enable_clocks(mcspi)) > + if (omap2_mcspi_enable_clocks(mcspi) < 0) > return -ENODEV; > > ret = omap2_mcspi_setup_transfer(spi, NULL); > @@ -1091,10 +1062,11 @@ static void omap2_mcspi_work(struct work_struct *work) > struct omap2_mcspi *mcspi; > > mcspi = container_of(work, struct omap2_mcspi, work); > - spin_lock_irq(&mcspi->lock); > > if (omap2_mcspi_enable_clocks(mcspi)) > - goto out; > + return; > + > + spin_lock_irq(&mcspi->lock); > > /* We only enable one channel at a time -- the one whose message is > * at the head of the queue -- although this controller would gladly > @@ -1169,7 +1141,7 @@ static void omap2_mcspi_work(struct work_struct *work) > /* RX_ONLY mode needs dummy data in TX reg */ > if (t->tx_buf == NULL) > __raw_writel(0, cs->base > - + OMAP2_MCSPI_TX0); > + + mcspi->regs[OMAP2_MCSPI_TX0]); > > if (m->is_dma_mapped || > t->len >= DMA_MIN_BYTES || > @@ -1218,10 +1190,9 @@ static void omap2_mcspi_work(struct work_struct *work) > spin_lock_irq(&mcspi->lock); > } > > - omap2_mcspi_disable_clocks(mcspi); > - > -out: > spin_unlock_irq(&mcspi->lock); > + > + omap2_mcspi_disable_clocks(mcspi); > } > > static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m) > @@ -1315,21 +1286,9 @@ static int __init omap2_mcspi_reset(struct omap2_mcspi *mcspi) > u32 tmp; > u32 error = 0; > > - if (omap2_mcspi_enable_clocks(mcspi)) > + if (omap2_mcspi_enable_clocks(mcspi) < 0) > return -1; > > - mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG, > - OMAP2_MCSPI_SYSCONFIG_SOFTRESET); > - do { > - tmp = mcspi_read_reg(master, OMAP2_MCSPI_SYSSTATUS); > - } while (!(tmp & OMAP2_MCSPI_SYSSTATUS_RESETDONE)); > - > - tmp = OMAP2_MCSPI_SYSCONFIG_AUTOIDLE | > - OMAP2_MCSPI_SYSCONFIG_ENAWAKEUP | > - OMAP2_MCSPI_SYSCONFIG_SMARTIDLE; > - mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG, tmp); > - omap2_mcspi_ctx[master->bus_num - 1].sysconfig = tmp; > - > tmp = OMAP2_MCSPI_WAKEUPENABLE_WKEN; > mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, tmp); > omap2_mcspi_ctx[master->bus_num - 1].wakeupenable = tmp; > @@ -1343,52 +1302,22 @@ static int __init omap2_mcspi_reset(struct omap2_mcspi *mcspi) > return error; > } > > -static u8 __initdata spi1_rxdma_id [] = { > - OMAP24XX_DMA_SPI1_RX0, > - OMAP24XX_DMA_SPI1_RX1, > - OMAP24XX_DMA_SPI1_RX2, > - OMAP24XX_DMA_SPI1_RX3, > -}; > - > -static u8 __initdata spi1_txdma_id [] = { > - OMAP24XX_DMA_SPI1_TX0, > - OMAP24XX_DMA_SPI1_TX1, > - OMAP24XX_DMA_SPI1_TX2, > - OMAP24XX_DMA_SPI1_TX3, > -}; > - > -static u8 __initdata spi2_rxdma_id[] = { > - OMAP24XX_DMA_SPI2_RX0, > - OMAP24XX_DMA_SPI2_RX1, > -}; > - > -static u8 __initdata spi2_txdma_id[] = { > - OMAP24XX_DMA_SPI2_TX0, > - OMAP24XX_DMA_SPI2_TX1, > -}; > - > -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \ > - || defined(CONFIG_ARCH_OMAP4) > -static u8 __initdata spi3_rxdma_id[] = { > - OMAP24XX_DMA_SPI3_RX0, > - OMAP24XX_DMA_SPI3_RX1, > -}; > +static int omap_mcspi_runtime_suspend(struct device *dev) > +{ > + return 0; > +} > > -static u8 __initdata spi3_txdma_id[] = { > - OMAP24XX_DMA_SPI3_TX0, > - OMAP24XX_DMA_SPI3_TX1, > -}; > -#endif > +static int omap_mcspi_runtime_resume(struct device *dev) > +{ > + struct omap2_mcspi *mcspi; > + struct spi_master *master; > > -#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) > -static u8 __initdata spi4_rxdma_id[] = { > - OMAP34XX_DMA_SPI4_RX0, > -}; > + master = dev_get_drvdata(dev); > + mcspi = spi_master_get_devdata(master); > + omap2_mcspi_restore_ctx(mcspi); > > -static u8 __initdata spi4_txdma_id[] = { > - OMAP34XX_DMA_SPI4_TX0, > -}; > -#endif > + return 0; > +} > > static int __init omap2_mcspi_probe(struct platform_device *pdev) > { > @@ -1398,38 +1327,6 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev) > struct omap2_mcspi *mcspi; > struct resource *r; > int status = 0, i; > - const u8 *rxdma_id, *txdma_id; > - unsigned num_chipselect; > - > - switch (pdev->id) { > - case 1: > - rxdma_id = spi1_rxdma_id; > - txdma_id = spi1_txdma_id; > - num_chipselect = 4; > - break; > - case 2: > - rxdma_id = spi2_rxdma_id; > - txdma_id = spi2_txdma_id; > - num_chipselect = 2; > - break; > -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \ > - || defined(CONFIG_ARCH_OMAP4) > - case 3: > - rxdma_id = spi3_rxdma_id; > - txdma_id = spi3_txdma_id; > - num_chipselect = 2; > - break; > -#endif > -#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) > - case 4: > - rxdma_id = spi4_rxdma_id; > - txdma_id = spi4_txdma_id; > - num_chipselect = 1; > - break; > -#endif > - default: > - return -EINVAL; > - } This seems appropriate. It makes sense to make things like assigned dma ids more data driven and remove the hard coded case tables. > > master = spi_alloc_master(&pdev->dev, sizeof *mcspi); > if (master == NULL) { > @@ -1446,7 +1343,7 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev) > master->setup = omap2_mcspi_setup; > master->transfer = omap2_mcspi_transfer; > master->cleanup = omap2_mcspi_cleanup; > - master->num_chipselect = num_chipselect; > + master->num_chipselect = pdata->num_cs; > > dev_set_drvdata(&pdev->dev, master); > > @@ -1455,6 +1352,7 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev) > mcspi->mcspi_mode = OMAP2_MCSPI_MASTER; > mcspi->dma_mode = pdata->dma_mode; > mcspi->force_cs_mode = pdata->force_cs_mode; > + mcspi->regs = pdata->regs_data; > > if (pdata->fifo_depth <= OMAP2_MCSPI_MAX_FIFODEPTH) > mcspi->fifo_depth = pdata->fifo_depth; > @@ -1479,63 +1377,67 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev) > if (!mcspi->base) { > dev_dbg(&pdev->dev, "can't ioremap MCSPI\n"); > status = -ENOMEM; > - goto err1aa; > + goto err2; > } > > + mcspi->dev = &pdev->dev; > INIT_WORK(&mcspi->work, omap2_mcspi_work); > > spin_lock_init(&mcspi->lock); > INIT_LIST_HEAD(&mcspi->msg_queue); > INIT_LIST_HEAD(&omap2_mcspi_ctx[master->bus_num - 1].cs); > > - mcspi->ick = clk_get(&pdev->dev, "ick"); > - if (IS_ERR(mcspi->ick)) { > - dev_dbg(&pdev->dev, "can't get mcspi_ick\n"); > - status = PTR_ERR(mcspi->ick); > - goto err1a; > - } > - mcspi->fck = clk_get(&pdev->dev, "fck"); > - if (IS_ERR(mcspi->fck)) { > - dev_dbg(&pdev->dev, "can't get mcspi_fck\n"); > - status = PTR_ERR(mcspi->fck); > - goto err2; > - } > - I'm obviously missing some context here. The driver doesn't seem to manage the clocks anymore. What code does now? > mcspi->dma_channels = kcalloc(master->num_chipselect, > sizeof(struct omap2_mcspi_dma), > GFP_KERNEL); > > if (mcspi->dma_channels == NULL) > - goto err3; > + goto err2; > > - for (i = 0; i < num_chipselect; i++) { > + for (i = 0; i < pdata->num_cs; i++) { > + char dma_ch_name[14]; > + struct resource *dma_res; > + > + sprintf(dma_ch_name, "rx%d", i); > + dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, > + dma_ch_name); > + if (!dma_res) { > + dev_dbg(&pdev->dev, "cannot get DMA RX channel\n"); > + status = -ENODEV; > + break; > + } > mcspi->dma_channels[i].dma_rx_channel = -1; > - mcspi->dma_channels[i].dma_rx_sync_dev = rxdma_id[i]; > + mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start; > + > + sprintf(dma_ch_name, "tx%d", i); > + dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, > + dma_ch_name); > + if (!dma_res) { > + dev_dbg(&pdev->dev, "cannot get DMA TX channel\n"); > + status = -ENODEV; > + break; > + } > mcspi->dma_channels[i].dma_tx_channel = -1; > - mcspi->dma_channels[i].dma_tx_sync_dev = txdma_id[i]; > + mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start; > } > > - if (omap2_mcspi_reset(mcspi) < 0) > - goto err4; > + pm_runtime_enable(&pdev->dev); > + if (status || omap2_mcspi_reset(mcspi) < 0) > + goto err3; > > status = spi_register_master(master); > if (status < 0) > goto err4; > > return status; > - > err4: > - kfree(mcspi->dma_channels); > + spi_master_put(master); > err3: > - clk_put(mcspi->fck); > + kfree(mcspi->dma_channels); > err2: > - clk_put(mcspi->ick); > -err1a: > - iounmap(mcspi->base); > -err1aa: > release_mem_region(r->start, (r->end - r->start) + 1); > + iounmap(mcspi->base); > err1: > - spi_master_put(master); > return status; > } > > @@ -1551,9 +1453,7 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev) > mcspi = spi_master_get_devdata(master); > dma_channels = mcspi->dma_channels; > > - clk_put(mcspi->fck); > - clk_put(mcspi->ick); > - > + omap2_mcspi_disable_clocks(mcspi); > r = platform_get_resource(pdev, IORESOURCE_MEM, 0); > release_mem_region(r->start, (r->end - r->start) + 1); > > @@ -1568,15 +1468,20 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev) > /* work with hotplug and coldplug */ > MODULE_ALIAS("platform:omap2_mcspi"); > > +static const struct dev_pm_ops omap_mcspi_dev_pm_ops = { > + .runtime_suspend = omap_mcspi_runtime_suspend, > + .runtime_resume = omap_mcspi_runtime_resume, > +}; > + > static struct platform_driver omap2_mcspi_driver = { > .driver = { > - .name = "omap2_mcspi", > - .owner = THIS_MODULE, > + .name = "omap2_mcspi", > + .owner = THIS_MODULE, > + .pm = &omap_mcspi_dev_pm_ops, nit: Unrelated whitespace changes. > }, > .remove = __exit_p(omap2_mcspi_remove), > }; > > - > static int __init omap2_mcspi_init(void) > { > omap2_mcspi_wq = create_singlethread_workqueue( > -- > 1.6.3.3 > > -- Grant Likely, B.Sc., P.Eng. Secret Lab Technologies Ltd. -- 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