From 5fdd1c7836674359b48ddeea5e5e1052191988cb Mon Sep 17 00:00:00 2001 From: Todd Doucet Date: Wed, 3 Feb 2010 17:18:29 -0500 Subject: Inital support for Digi CoreConnect Wi-i.MX51 Devlopment Kit Supports: LCD and VGA frambuffer Touchscreen Audio out USB host SD/MMC Ethernet Serial I2C --- arch/arm/mach-mx51/devices.c | 3 +- arch/arm/mach-mx51/dummy_gpio.c | 12 -- arch/arm/mach-mx51/mx51_ccwmx51js.c | 167 ++++++++------- arch/arm/mach-mx51/mx51_ccwmx51js_gpio.c | 203 +++++++++++++++++- arch/arm/plat-mxc/dvfs_core.c | 3 +- drivers/i2c/busses/mxc_i2c.c | 4 - drivers/usb/core/hcd.c | 5 +- sound/soc/imx/Kconfig | 9 + sound/soc/imx/Makefile | 3 +- sound/soc/imx/imx-ccwmx51js-wm8753.c | 342 +++++++++++++++++++++++++++++++ 10 files changed, 660 insertions(+), 91 deletions(-) create mode 100644 sound/soc/imx/imx-ccwmx51js-wm8753.c diff --git a/arch/arm/mach-mx51/devices.c b/arch/arm/mach-mx51/devices.c index 3496580d807f..9f015d43640f 100644 --- a/arch/arm/mach-mx51/devices.c +++ b/arch/arm/mach-mx51/devices.c @@ -596,6 +596,7 @@ extern void mx51_babbage_gpio_spi_chipselect_active(int cspi_mode, int status, int chipselect); extern void mx51_babbage_gpio_spi_chipselect_inactive(int cspi_mode, int status, int chipselect); + /*! Platform Data for MXC CSPI1 */ static struct mxc_spi_master mxcspi1_data = { .maxchipselect = 4, @@ -693,7 +694,7 @@ void __init mxc_init_spi(void) /* SPBA configuration for CSPI2 - MCU is set */ spba_take_ownership(SPBA_CSPI1, SPBA_MASTER_A); #ifdef CONFIG_SPI_MXC_SELECT1 - if (machine_is_mx51_babbage()) { + if (machine_is_ccwmx51() || machine_is_mx51_babbage()) { mxcspi1_data.chipselect_active = mx51_babbage_gpio_spi_chipselect_active; mxcspi1_data.chipselect_inactive = diff --git a/arch/arm/mach-mx51/dummy_gpio.c b/arch/arm/mach-mx51/dummy_gpio.c index bf21862908ac..57bddb92cafe 100644 --- a/arch/arm/mach-mx51/dummy_gpio.c +++ b/arch/arm/mach-mx51/dummy_gpio.c @@ -23,12 +23,6 @@ EXPORT_SYMBOL(gpio_gps_inactive); void config_uartdma_event(int port) {} EXPORT_SYMBOL(config_uartdma_event); -void gpio_spi_active(int cspi_mod) {} -EXPORT_SYMBOL(gpio_spi_active); - -void gpio_spi_inactive(int cspi_mod) {} -EXPORT_SYMBOL(gpio_spi_inactive); - void gpio_owire_active(void) {} EXPORT_SYMBOL(gpio_owire_active); @@ -73,12 +67,6 @@ EXPORT_SYMBOL(gpio_ata_active); void gpio_ata_inactive(void) {} EXPORT_SYMBOL(gpio_ata_inactive); -void gpio_nand_active(void) {} -EXPORT_SYMBOL(gpio_nand_active); - -void gpio_nand_inactive(void) {} -EXPORT_SYMBOL(gpio_nand_inactive); - void gpio_keypad_active(void) {} EXPORT_SYMBOL(gpio_keypad_active); diff --git a/arch/arm/mach-mx51/mx51_ccwmx51js.c b/arch/arm/mach-mx51/mx51_ccwmx51js.c index 2d603bb3655e..f538fa0e4bfc 100644 --- a/arch/arm/mach-mx51/mx51_ccwmx51js.c +++ b/arch/arm/mach-mx51/mx51_ccwmx51js.c @@ -1,6 +1,7 @@ /* * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2009 Digi International, Inc. All Rights Reserved. + * Copyright 2010 Timesys Corporation. All Rights Reserved. */ /* @@ -111,53 +112,6 @@ static void mxc_nop_release(struct device *dev) /* Nothing */ } -/* MTD NAND flash */ -#if defined(CONFIG_MTD_NAND_MXC) \ - || defined(CONFIG_MTD_NAND_MXC_MODULE) \ - || defined(CONFIG_MTD_NAND_MXC_V2) \ - || defined(CONFIG_MTD_NAND_MXC_V2_MODULE) \ - || defined(CONFIG_MTD_NAND_MXC_V3) \ - || defined(CONFIG_MTD_NAND_MXC_V3_MODULE) - -extern void gpio_nand_active(void); -extern void gpio_nand_inactive(void); - -static int nand_init(void) -{ - /* Configure the pins */ - gpio_nand_active(); - return 0; -} - -static void nand_exit(void) -{ - /* Free the pins */ - gpio_nand_inactive(); -} - -static struct flash_platform_data mxc_nand_data = { - .width = 1, - .init = nand_init, - .exit = nand_exit, -}; - -static struct platform_device mxc_nandv2_mtd_device = { - .name = "mxc_nandv2_flash", - .id = 0, - .dev = { - .release = mxc_nop_release, - .platform_data = &mxc_nand_data, - }, -}; - -static void ccwmx51_init_nand_mtd(void) -{ - (void)platform_device_register(&mxc_nandv2_mtd_device); -} -#else -static inline void ccwmx51_init_nand_mtd(void) { } -#endif - #if defined(CONFIG_SMSC9118) static struct resource smsc911x_device_resources[] = { [0] = { @@ -226,7 +180,7 @@ static void ccwmx51_init_ext_eth_mac(void) (void)platform_device_register(&smsc911x_device); } #else -static void ccwmx51_init_ext_eth_mac(void) { } +//static void ccwmx51_init_ext_eth_mac(void) { } #endif @@ -364,11 +318,33 @@ static inline void ccwmx51_init_mmc(void) {} #if defined(CONFIG_FB_MXC_SYNC_PANEL) || \ defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) +static struct fb_videomode wvga_video_mode = +{ + .name = "Digi LCD", + .xres = 800, + .yres = 480, + .refresh = 60, + .pixclock = 30062, + .left_margin = 64, + .right_margin = 64, + .lower_margin = 10, + .upper_margin = 30, + .hsync_len = 128, + .vsync_len = 5, + .vmode = FB_VMODE_NONINTERLACED, + .flag = FB_MODE_IS_DETAILED, +// Digi says that inverting the clock is necessary +// to avoid problems with video. +// .sync = FB_SYNC_CLK_LAT_FALL, + +}; + + static struct mxc_fb_platform_data fb_data_vga = { .interface_pix_fmt = IPU_PIX_FMT_RGB24, - .mode_str = "1024x768M-16@60", /* Default */ }; + static struct platform_device mxc_fb_device[] = { { .name = "mxc_sdc_fb", @@ -376,7 +352,7 @@ static struct platform_device mxc_fb_device[] = { .dev = { .release = mxc_nop_release, .coherent_dma_mask = 0xFFFFFFFF, - .platform_data = &fb_data_vga, + .platform_data = &fb_data_vga }, }, { .name = "mxc_sdc_fb", @@ -384,7 +360,6 @@ static struct platform_device mxc_fb_device[] = { .dev = { .release = mxc_nop_release, .coherent_dma_mask = 0xFFFFFFFF, - .platform_data = NULL, }, }, { .name = "mxc_sdc_fb", @@ -396,41 +371,64 @@ static struct platform_device mxc_fb_device[] = { }, }; +extern void gpio_lcd_active(void); + + +// We let the user specify e.g. 800x600x24, but pay attention +// only to the 800x600 part, and use 24-bit color regardless. +static int video_matches(char *user, char *template) +{ + return !strncasecmp(user, template, strlen(template)); +} + static int __init ccwmx51_init_fb(void) { char *options = NULL, *p; if (fb_get_options("displayfb", &options)) - pr_warning("no display information available in commnad line\n"); + pr_warning("no display information available in command line\n"); if (!options) return -ENODEV; if (!strncasecmp(options, "VGA", 3)) { pr_info("VGA interface is primary\n"); + + fb_data_vga.mode = 0; // Do not use LCD timings. + fb_data_vga.mode_str = "1024x768M-16@60"; /* Default */ /* Get the desired configuration provided by the bootloader */ if (options[3] != '@') { - pr_info("Video resolution for VGA interface not provided, using default\n"); - /* TODO set default video here */ + pr_info("Video resolution for VGA interface not provided, using '%s'\n", + fb_data_vga.mode_str); } else { options = &options[4]; if (((p = strsep (&options, "@")) != NULL) && *p) { - if (!strcmp(p, "640x480x16")) { - strcpy(fb_data_vga.mode_str, "640x480M-16@60"); - } else if (!strcmp(p, "800x600x16")) { - strcpy(fb_data_vga.mode_str, "800x600M-16@60"); - } else if (!strcmp(p, "1024x768x16")) { - strcpy(fb_data_vga.mode_str, "1024x768M-16@60"); - } else if (!strcmp(p, "1280x1024x16")) { - strcpy(fb_data_vga.mode_str, "1280x1024M-16@60"); - } else if (!strcmp(p, "1280x1024x16")) { - strcpy(fb_data_vga.mode_str, "1280x1024M-16@60"); + if (video_matches(p, "640x480") ){ + fb_data_vga.mode_str = "640x480M-16@60"; + } else if (video_matches(p, "800x600")) { + fb_data_vga.mode_str = "800x600M-16@60"; + } else if (video_matches(p, "1024x768")) { + fb_data_vga.mode_str = "1024x768M-16@60"; + } else if (video_matches(p, "1280x1024")) { + fb_data_vga.mode_str = "1280x1024M-16@60"; + } else if (video_matches(p, "1280x1024")) { + fb_data_vga.mode_str = "1280x1024M-16@60"; + } else if (video_matches(p, "1280x768")) { + fb_data_vga.mode_str = "1280x768M-16@60"; } else - pr_warning("Unsuported video resolution: %s, using default\n", p); + pr_warning("Unsupported video resolution: %s, using default '%s'\n", + p, fb_data_vga.mode_str); } } - (void)platform_device_register(&mxc_fb_device[0]); /* VGA */ + platform_device_register(&mxc_fb_device[0]); /* VGA */ + + } else if (!strncasecmp(options, "LCD", 3)){ + gpio_lcd_active(); + fb_data_vga.mode = &wvga_video_mode; // Use timings for Digi LCD. + fb_data_vga.mode_str = "800x480-16@60", // 16-bit color more compatible with Factory apps + pr_info("Using LDC wvga video timings and mode %s\n", fb_data_vga.mode_str); + platform_device_register(&mxc_fb_device[0]); /* LCD */ } return 0; @@ -503,19 +501,47 @@ static void mxc_power_off(void) static struct i2c_board_info ccwmx51_i2c_devices[] __initdata = { #if defined(CONFIG_INPUT_MMA7455L) + // accelerometer, unsupported at present. { I2C_BOARD_INFO("mma7455l", 0x1d), .irq = IOMUX_TO_IRQ(MX51_PIN_GPIO1_7), }, #endif + + + + }; -int __init ccwmx51_init_mma7455l(void) + +int __init ccwmx51_i2c_setup(void) { return i2c_register_board_info(1, ccwmx51_i2c_devices , ARRAY_SIZE(ccwmx51_i2c_devices) ); } +static struct mxc_audio_platform_data wm8753_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 3, + .sysclk = 11289600, // So we can do 44.1 kHz +}; + +static struct platform_device mxc_wm8753_device = { + .name = "imx-ccwmx51js-wm8753", + .dev = { + .release = mxc_nop_release, + .platform_data = &wm8753_data, + }, +}; + + +static void mxc_init_wm8753(void) +{ + platform_device_register(&mxc_wm8753_device); +} + + /*! * Board specific initialization. */ @@ -528,10 +554,11 @@ static void __init mxc_board_init(void) mxc_init_devices(); ccwmx51_init_mmc(); - ccwmx51_init_nand_mtd(); -// ccwmx51_init_ext_eth_mac(); - ccwmx51_init_mma7455l(); + + ccwmx51_i2c_setup(); ccwmx51_init_mc13892(); + mxc_init_wm8753(); + pm_power_off = mxc_power_off; } diff --git a/arch/arm/mach-mx51/mx51_ccwmx51js_gpio.c b/arch/arm/mach-mx51/mx51_ccwmx51js_gpio.c index 3458935cd8cf..0745c89c0625 100644 --- a/arch/arm/mach-mx51/mx51_ccwmx51js_gpio.c +++ b/arch/arm/mach-mx51/mx51_ccwmx51js_gpio.c @@ -207,6 +207,12 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_usbh1_pins[] = { #if defined(CONFIG_FB_MXC_SYNC_PANEL) || defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_video1_pins[] = { + // This pin is necessary to enable the Digi LCD panel on the P1 + // connector. + { + MX51_PIN_DI1_PIN11, IOMUX_CONFIG_ALT4, + (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), + }, { /* DISP1 DAT0 */ MX51_PIN_DISP1_DAT0, IOMUX_CONFIG_ALT0, (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST), @@ -359,6 +365,32 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_mma7455l_pins[] = { #endif //defined(CONFIG_I2C_MXC) || defined(CONFIG_I2C_MXC_MODULE) static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_devices_pins[] = { + { + MX51_PIN_AUD3_BB_TXD, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_100K_PU | PAD_CTL_HYS_NONE | PAD_CTL_DDR_INPUT_CMOS | + PAD_CTL_DRV_VOT_LOW), + }, + { + MX51_PIN_AUD3_BB_RXD, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_100K_PU | PAD_CTL_HYS_NONE | PAD_CTL_DDR_INPUT_CMOS | + PAD_CTL_DRV_VOT_LOW), + }, + { + MX51_PIN_AUD3_BB_CK, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_100K_PU | PAD_CTL_HYS_NONE | PAD_CTL_DDR_INPUT_CMOS | + PAD_CTL_DRV_VOT_LOW), + }, + { + MX51_PIN_AUD3_BB_FS, IOMUX_CONFIG_ALT0, + (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_100K_PU | PAD_CTL_HYS_NONE | PAD_CTL_DDR_INPUT_CMOS | + PAD_CTL_DRV_VOT_LOW), + }, + + { /* PMIC interrupt line */ MX51_PIN_GPIO1_5, IOMUX_CONFIG_GPIO | IOMUX_CONFIG_SION, (PAD_CTL_SRE_SLOW | PAD_CTL_DRV_MEDIUM | PAD_CTL_100K_PU | @@ -422,13 +454,15 @@ void __init ccwmx51_io_init(void) #if defined(CONFIG_FB_MXC_SYNC_PANEL) || defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_video1_pins); i++) { mxc_request_iomux(ccwmx51_iomux_video1_pins[i].pin, - ccwmx51_iomux_video1_pins[i].mux_mode); + ccwmx51_iomux_video1_pins[i].mux_mode); if (ccwmx51_iomux_video1_pins[i].pad_cfg) mxc_iomux_set_pad(ccwmx51_iomux_video1_pins[i].pin, ccwmx51_iomux_video1_pins[i].pad_cfg); + if (ccwmx51_iomux_video1_pins[i].in_select) mxc_iomux_set_input(ccwmx51_iomux_video1_pins[i].in_select, ccwmx51_iomux_video1_pins[i].in_mode); + } #endif @@ -470,6 +504,15 @@ void __init ccwmx51_io_init(void) } +void gpio_lcd_active(void) +{ + gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DI1_PIN11), 0); +} + + +EXPORT_SYMBOL(gpio_lcd_active); + + #if defined(CONFIG_SERIAL_MXC) || defined(CONFIG_SERIAL_MXC_MODULE) #define SERIAL_PORT_PAD (PAD_CTL_HYS_ENABLE | PAD_CTL_PKE_ENABLE | \ PAD_CTL_PUE_PULL | PAD_CTL_DRV_HIGH | \ @@ -526,3 +569,161 @@ void gpio_uart_active(int port, int no_irda) {} void gpio_uart_inactive(int port, int no_irda) {} EXPORT_SYMBOL(gpio_uart_active); EXPORT_SYMBOL(gpio_uart_inactive); + + + +/*! + * Setup GPIO for a CSPI device to be active + * + * @param cspi_mod an CSPI device + */ + +void gpio_spi_active(int cspi_mod) +{ + switch (cspi_mod) { + case 0: + /* SPI1 */ + mxc_request_iomux(MX51_PIN_CSPI1_MOSI, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX51_PIN_CSPI1_MISO, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX51_PIN_CSPI1_SCLK, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX51_PIN_CSPI1_SS0, IOMUX_CONFIG_ALT0); + + mxc_iomux_set_pad(MX51_PIN_CSPI1_MOSI, + PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | + PAD_CTL_DRV_HIGH | + PAD_CTL_SRE_FAST + ); + + mxc_iomux_set_pad(MX51_PIN_CSPI1_MISO, + PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | + PAD_CTL_DRV_HIGH | + PAD_CTL_SRE_FAST + ); + + mxc_iomux_set_pad(MX51_PIN_CSPI1_SCLK, + PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | + PAD_CTL_DRV_HIGH | + PAD_CTL_SRE_FAST + ); + + + mxc_iomux_set_pad(MX51_PIN_CSPI1_SS0, + PAD_CTL_SRE_FAST + ); + + break; + case 1: + /* SPI2 */ + break; + default: + break; + } +} + + +EXPORT_SYMBOL(gpio_spi_active); + +/*! + * Setup GPIO for a CSPI device to be inactive + * + * @param cspi_mod a CSPI device + */ +void gpio_spi_inactive(int cspi_mod) +{ +} + +EXPORT_SYMBOL(gpio_spi_inactive); + + +/* + * + * Investigating ecSPI issue. + * + */ + +// copied from babbage code. +/* workaround for ecspi chipselect pin may not keep correct level when idle */ +void mx51_babbage_gpio_spi_chipselect_active(int cspi_mode, int status, + int chipselect) +{ + u32 gpio; + int r = 0; + + switch (cspi_mode) { + case 1: + switch (chipselect) { + case 0x1: + r = mxc_request_iomux(MX51_PIN_CSPI1_SS0, + IOMUX_CONFIG_ALT0); + if (r){ + printk("mxc_request_iomux could not get ss0\n"); + } + mxc_iomux_set_pad(MX51_PIN_CSPI1_SS0, + PAD_CTL_HYS_ENABLE | + PAD_CTL_PKE_ENABLE | + PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST); + + break; + case 0x2: + gpio = IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS0); + r = mxc_request_iomux(MX51_PIN_CSPI1_SS0, + IOMUX_CONFIG_GPIO); + if (r){ + printk("mxc_request_iomux could not get ss0 in case 2\n"); + } + r = gpio_request(gpio, "cspi1_ss0"); + if (r){ + printk("gpio_request(cspi1_ss0) failed\n"); + } + r = gpio_direction_output(gpio, 0); + if (r){ + printk("gpio_set_direction_output(cspi1_ss0) failed\n"); + } + gpio_set_value(gpio, 1 & (~status)); + break; + default: + break; + } + break; + case 2: + break; + case 3: + break; + default: + break; + } +} +EXPORT_SYMBOL(mx51_babbage_gpio_spi_chipselect_active); + +void mx51_babbage_gpio_spi_chipselect_inactive(int cspi_mode, int status, + int chipselect) +{ + switch (cspi_mode) { + case 1: + switch (chipselect) { + case 0x1: + mxc_free_iomux(MX51_PIN_CSPI1_SS0, IOMUX_CONFIG_ALT0); + mxc_request_iomux(MX51_PIN_CSPI1_SS0, + IOMUX_CONFIG_GPIO); + mxc_free_iomux(MX51_PIN_CSPI1_SS0, IOMUX_CONFIG_GPIO); + break; + case 0x2: + mxc_free_iomux(MX51_PIN_CSPI1_SS0, IOMUX_CONFIG_GPIO); + break; + default: + break; + } + break; + case 2: + break; + case 3: + break; + default: + break; + } +} +EXPORT_SYMBOL(mx51_babbage_gpio_spi_chipselect_inactive); + diff --git a/arch/arm/plat-mxc/dvfs_core.c b/arch/arm/plat-mxc/dvfs_core.c index 169c9feab697..1c09885fde30 100644 --- a/arch/arm/plat-mxc/dvfs_core.c +++ b/arch/arm/plat-mxc/dvfs_core.c @@ -829,8 +829,9 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev) old_wp = 0; curr_wp = 0; dvfs_core_resume = 0; +#if defined(CONFIG_CPU_FREQ) cpufreq_trig_needed = 0; - +#endif return err; err1: diff --git a/drivers/i2c/busses/mxc_i2c.c b/drivers/i2c/busses/mxc_i2c.c index f051419f02bc..0a43cdc88ab1 100644 --- a/drivers/i2c/busses/mxc_i2c.c +++ b/drivers/i2c/busses/mxc_i2c.c @@ -705,12 +705,8 @@ static int mxci2c_probe(struct platform_device *pdev) } } if (mxc_i2c->clkdiv == -1) { - i--; mxc_i2c->clkdiv = 0x1F; /* Use max divider */ } - dev_dbg(&pdev->dev, "i2c speed is %d/%d = %d bps, reg val = 0x%02X\n", - clk_freq, i2c_clk_table[i].div, - clk_freq / i2c_clk_table[i].div, mxc_i2c->clkdiv); /* * Set the adapter information diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 3208360664c8..5650778ef001 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -117,7 +117,7 @@ static inline int is_root_hub(struct usb_device *udev) return (udev->parent == NULL); } -#if CONFIG_PM +#ifdef CONFIG_PM extern int usb_host_wakeup_irq(struct device *wkup_dev); extern void usb_host_set_wakeup(struct device *wkup_dev, bool para); #endif @@ -1730,6 +1730,8 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) local_irq_save(flags); if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + +#ifdef CONFIG_PM /* if receive a remote wakeup interrrupt after suspend */ if (usb_host_wakeup_irq(hcd->self.controller)) { /* disable remote wake up irq */ @@ -1738,6 +1740,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) hcd->driver->irq(hcd); rc = IRQ_HANDLED; } else +#endif rc = IRQ_NONE; } else if (unlikely(hcd->state == HC_STATE_HALT)) { rc = IRQ_NONE; diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index c81f943a2e10..ddecb6ad62fe 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -37,6 +37,15 @@ config SND_SOC_IMX_3STACK_SGTL5000 Say Y if you want to add support for SoC audio on IMX 3STACK with the SGTL5000. + +config SND_SOC_IMX_CCWMX51JS + tristate "SoC Audio support for Digi CCWMX51JS" + select SND_MXC_SOC_SSI + select SND_SOC_WM8753 + help + Say Y if you want to add support for SoC audio on Digi + CCWMX51JS with the WM8753 codec. + config SND_SOC_IMX_3STACK_AK4647 tristate "SoC Audio support for IMX - AK4647" select SND_MXC_SOC_SSI diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile index 0460f965a85b..57c645ae7c44 100644 --- a/sound/soc/imx/Makefile +++ b/sound/soc/imx/Makefile @@ -20,4 +20,5 @@ snd-soc-imx-3stack-ak5702-objs := imx-3stack-ak5702.o obj-$(CONFIG_SND_SOC_IMX_3STACK_AK5702) += snd-soc-imx-3stack-ak5702.o snd-soc-imx-3stack-bt-objs := imx-3stack-bt.o obj-$(CONFIG_SND_SOC_IMX_3STACK_BLUETOOTH) += snd-soc-imx-3stack-bt.o - +snd-soc-imx-ccwmx51js-wm8753-objs := imx-ccwmx51js-wm8753.o +obj-$(CONFIG_SND_SOC_IMX_CCWMX51JS) += snd-soc-imx-ccwmx51js-wm8753.o diff --git a/sound/soc/imx/imx-ccwmx51js-wm8753.c b/sound/soc/imx/imx-ccwmx51js-wm8753.c new file mode 100644 index 000000000000..c9c4d425143f --- /dev/null +++ b/sound/soc/imx/imx-ccwmx51js-wm8753.c @@ -0,0 +1,342 @@ +/* + * imx-ccwmx51js-wm8753.c -- i.MX Driver for Digi CCWMS51JS and the Wolfson WM8753 Codec + * + * Adapted by Timesys from sgtl5000 machine driver and other sources. + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2010 Timesys Corpotation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Based on sound/soc/imx/imx-3stack-sgtl5000.c + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "../codecs/wm8753.h" +#include "imx-ssi.h" +#include "imx-pcm.h" + + +/* SSI BCLK and LRC master + * + * Set WM8753_SSI_MASTER to operate the WM8753 codec in master mode, + * and set to zero to operate it in slave mode. + */ +#define WM8753_SSI_MASTER 1 + + +struct ccwmx51_priv { + int sysclk; + struct platform_device *pdev; +}; + +static struct ccwmx51_priv machine_priv; + +static struct snd_soc_dai ccwmx51_cpu_dai; + + +static int ccwmx51js_audio_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai_link *machine = rtd->dai; + struct snd_soc_dai *cpu_dai = machine->cpu_dai; + struct snd_soc_dai *codec_dai = machine->codec_dai; + struct ccwmx51_priv *priv = &machine_priv; + int ret = 0; + + unsigned int channels = params_channels(params); + u32 dai_format; + + +#if WM8753_SSI_MASTER + dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_SYNC; + if (channels == 2) + dai_format |= SND_SOC_DAIFMT_TDM; + + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, dai_format); + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, dai_format); + + if (ret < 0) + return ret; +#else + dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_SYNC; + if (channels == 2) + dai_format |= SND_SOC_DAIFMT_TDM; + + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, dai_format); + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, dai_format); + + if (ret < 0) + return ret; +#endif + + snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, priv->sysclk, 0); + + /* set i.MX active slot mask */ + snd_soc_dai_set_tdm_slot(cpu_dai, + channels == 1 ? 0xfffffffe : 0xfffffffc, 2); + + /* set the SSI system clock as input (unused) */ + snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, SND_SOC_CLOCK_IN); + + + /* The WM8753 PLL on the Digi CCWMX51JS is referenced to a fixed 13-MHz + * oscillator. We presently operate the PLL only at 11.289600 + * MHz output, which supports a 44.1-kHz sample rate and a few others. + * + */ + + // set codec BCLK division for sample rate */ + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, WM8753_BCLK_DIV_4); + if (ret < 0) + return ret; + + // Specify input PLL frequency and desired output frequency. + ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 13000000, 11289600); + if (ret < 0) + return ret; + return 0; +} + + + + // Sets up the i.mx51 Digital Audio Multiplexer +static void ccwmx51_init_dam(int ssi_port, int dai_port) +{ + unsigned int ssi_ptcr = 0; + unsigned int dai_ptcr = 0; + unsigned int ssi_pdcr = 0; + unsigned int dai_pdcr = 0; + /* i.mx51 uses SSI1 or SSI2 via AUDMUX port dai_port for audio */ + + /* reset port ssi_port & dai_port */ + __raw_writel(0, DAM_PTCR(ssi_port)); + __raw_writel(0, DAM_PTCR(dai_port)); + __raw_writel(0, DAM_PDCR(ssi_port)); + __raw_writel(0, DAM_PDCR(dai_port)); + + /* set to synchronous */ + ssi_ptcr |= AUDMUX_PTCR_SYN; + dai_ptcr |= AUDMUX_PTCR_SYN; + +#if WM8753_SSI_MASTER + /* set Rx sources ssi_port <--> dai_port */ + ssi_pdcr |= AUDMUX_PDCR_RXDSEL(dai_port); + dai_pdcr |= AUDMUX_PDCR_RXDSEL(ssi_port); + + /* set Tx frame direction and source dai_port--> ssi_port output */ + ssi_ptcr |= AUDMUX_PTCR_TFSDIR; + ssi_ptcr |= AUDMUX_PTCR_TFSSEL(AUDMUX_FROM_TXFS, dai_port); + + /* set Tx Clock direction and source dai_port--> ssi_port output */ + ssi_ptcr |= AUDMUX_PTCR_TCLKDIR; + ssi_ptcr |= AUDMUX_PTCR_TCSEL(AUDMUX_FROM_TXFS, dai_port); +#else + /* set Rx sources ssi_port <--> dai_port */ + ssi_pdcr |= AUDMUX_PDCR_RXDSEL(dai_port); + dai_pdcr |= AUDMUX_PDCR_RXDSEL(ssi_port); + + /* set Tx frame direction and source ssi_port --> dai_port output */ + dai_ptcr |= AUDMUX_PTCR_TFSDIR; + dai_ptcr |= AUDMUX_PTCR_TFSSEL(AUDMUX_FROM_TXFS, ssi_port); + + /* set Tx Clock direction and source ssi_port--> dai_port output */ + dai_ptcr |= AUDMUX_PTCR_TCLKDIR; + dai_ptcr |= AUDMUX_PTCR_TCSEL(AUDMUX_FROM_TXFS, ssi_port); +#endif + + __raw_writel(ssi_ptcr, DAM_PTCR(ssi_port)); + __raw_writel(dai_ptcr, DAM_PTCR(dai_port)); + __raw_writel(ssi_pdcr, DAM_PDCR(ssi_port)); + __raw_writel(dai_pdcr, DAM_PDCR(dai_port)); +} + + + +/* + * Still to do: set the line out to become enabled within + * this driver. Currently the initial driver configuration + * has all outputs disabled. They can be enabled in user space + * by doing: + * + * amixer sset 'Left Mixer Left' unmute + * amixer sset 'Right Mixer Right Playback Swit' unmute + * + */ +static int ccwmx51js_startup(struct snd_pcm_substream *substream) +{ + return 0; +} + +static void ccwmx51js_shutdown(struct snd_pcm_substream *substream) +{ +} + +static struct snd_soc_ops ccwmx51js_ops = { + .startup = ccwmx51js_startup, + .shutdown = ccwmx51js_shutdown, + .hw_params = ccwmx51js_audio_hw_params, +}; + + + // Logic for wm8753 as connected on Digi CCWMX51JS board. +static int ccwmx51js_wm8753_init(struct snd_soc_codec *codec) +{ + return 0; +} + + +/* digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link ccwmx51js_dai = { + .name = "CCWMX51JS WM8753", + + .stream_name = "WM8753 HiFi", + .cpu_dai = &ccwmx51_cpu_dai, + .codec_dai = &wm8753_dai[WM8753_DAI_HIFI], + .init = ccwmx51js_wm8753_init, + .ops = &ccwmx51js_ops, +}; + +static int ccwmx51js_machine_remove(struct platform_device *pdev) +{ + struct ccwmx51_priv *priv = &machine_priv; + struct mxc_audio_platform_data *plat; + + if (priv->pdev) { + plat = priv->pdev->dev.platform_data; + if (plat->finit) + plat->finit(); + } + + return 0; +} + +/* audio machine driver */ +static struct snd_soc_machine snd_soc_machine_ccwmx51js = { + .name = "imx-ccwmx51js", + .dai_link = &ccwmx51js_dai, + .num_links = 1, + .remove = ccwmx51js_machine_remove, +}; + +static struct wm8753_setup_data ccwmx51_wm8753_setup = { + .i2c_address = 0x1a, + .i2c_bus = 1, +}; + +static struct snd_soc_device ccwmx51js_snd_devdata = { + .machine = &snd_soc_machine_ccwmx51js, + .platform = &imx_soc_platform, + .codec_dev = &soc_codec_dev_wm8753, + .codec_data = &ccwmx51_wm8753_setup, +}; + +static int __devinit ccwmx51js_wm8753_probe(struct platform_device *pdev) +{ + struct mxc_audio_platform_data *plat = pdev->dev.platform_data; + struct ccwmx51_priv *priv = &machine_priv; + int ret = 0; + + priv->sysclk = plat->sysclk; + priv->pdev = pdev; + + imx_ssi_dai_init(&ccwmx51_cpu_dai); + ccwmx51_cpu_dai.private_data = plat; + + ccwmx51_init_dam(plat->src_port, plat->ext_port); + + if (plat->src_port == 2) + ccwmx51_cpu_dai.name = "imx-ssi-3"; + else + ccwmx51_cpu_dai.name = "imx-ssi-1"; + + ret = -EINVAL; + if (plat->init && plat->init()){ + goto err_plat_init; + } + return 0; + +err_plat_init: + return ret; +} + +static int ccwmx51js_wm8753_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver ccwmx51js_wm8753_audio_driver = { + .probe = ccwmx51js_wm8753_probe, + .remove = ccwmx51js_wm8753_remove, + .driver = { + .name = "imx-ccwmx51js-wm8753", + }, +}; + +static struct platform_device *ccwmx51js_snd_device; + +static int __init ccwmx51js_init(void) +{ + int ret; + + ret = platform_driver_register(&ccwmx51js_wm8753_audio_driver); + if (ret) + return -ENOMEM; + + ccwmx51js_snd_device = platform_device_alloc("soc-audio", -1); + if (!ccwmx51js_snd_device) + return -ENOMEM; + + platform_set_drvdata(ccwmx51js_snd_device, &ccwmx51js_snd_devdata); + ccwmx51js_snd_devdata.dev = &ccwmx51js_snd_device->dev; + ret = platform_device_add(ccwmx51js_snd_device); + + if (ret) + platform_device_put(ccwmx51js_snd_device); + + return ret; +} + +static void __exit ccwmx51js_exit(void) +{ + platform_driver_unregister(&ccwmx51js_wm8753_audio_driver); + platform_device_unregister(ccwmx51js_snd_device); +} + +module_init(ccwmx51js_init); +module_exit(ccwmx51js_exit); + +MODULE_AUTHOR("Timesys"); +MODULE_DESCRIPTION("WM8753 Driver for Digi CCWMX51JS"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3