summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Wisbon <ian.wisbon@timesys.com>2011-02-10 17:15:15 -0500
committerIan Wisbon <ian.wisbon@timesys.com>2011-02-10 17:15:15 -0500
commita9d2ba1444b0af6c2d8534f0b306660ffc045bc6 (patch)
tree79b396bf70ae3795e6ee9a3b645e64f7e29474e7
parenteffff5718c380983788fe6c380671c18e15ac7c2 (diff)
Linux 2.6.31 Release for Digi ConnectCore Wi-i.MX boards2.6.31-digi-201102101717
-rw-r--r--arch/arm/Kconfig2
-rw-r--r--arch/arm/configs/imx23evk_defconfig208
-rw-r--r--arch/arm/configs/imx28evk_defconfig67
-rw-r--r--arch/arm/configs/imx28evk_updater_defconfig257
-rw-r--r--arch/arm/configs/imx35_3stack_defconfig30
-rw-r--r--arch/arm/configs/imx35_updater_defconfig579
-rw-r--r--arch/arm/configs/imx5_defconfig66
-rw-r--r--arch/arm/include/asm/mach/flash.h1
-rw-r--r--arch/arm/mach-mx23/Kconfig16
-rw-r--r--arch/arm/mach-mx23/Makefile1
-rw-r--r--arch/arm/mach-mx23/bus_freq.c82
-rw-r--r--arch/arm/mach-mx23/clock.c962
-rw-r--r--arch/arm/mach-mx23/device.c237
-rw-r--r--arch/arm/mach-mx23/emi.S93
-rw-r--r--arch/arm/mach-mx23/emi.inc68
-rw-r--r--arch/arm/mach-mx23/include/mach/lcdif.h171
-rw-r--r--arch/arm/mach-mx23/include/mach/mx23.h6
-rw-r--r--arch/arm/mach-mx23/mx23_pins.h2
-rw-r--r--arch/arm/mach-mx23/mx23evk.c41
-rw-r--r--arch/arm/mach-mx23/mx23evk.h6
-rw-r--r--arch/arm/mach-mx23/mx23evk_pins.c544
-rw-r--r--arch/arm/mach-mx23/pm.c2
-rw-r--r--arch/arm/mach-mx23/usb_dr.c32
-rw-r--r--arch/arm/mach-mx25/devices.c49
-rw-r--r--arch/arm/mach-mx25/mx25_3stack.c35
-rw-r--r--arch/arm/mach-mx25/mx25_3stack_gpio.c8
-rw-r--r--arch/arm/mach-mx25/usb_dr.c24
-rw-r--r--arch/arm/mach-mx28/Kconfig10
-rw-r--r--arch/arm/mach-mx28/bus_freq.c80
-rw-r--r--arch/arm/mach-mx28/clock.c82
-rw-r--r--arch/arm/mach-mx28/device.c380
-rw-r--r--arch/arm/mach-mx28/emi_settings.c1
-rw-r--r--arch/arm/mach-mx28/include/mach/mx28.h5
-rw-r--r--arch/arm/mach-mx28/mx28evk.c7
-rw-r--r--arch/arm/mach-mx28/mx28evk.h5
-rw-r--r--arch/arm/mach-mx28/mx28evk_pins.c287
-rw-r--r--arch/arm/mach-mx28/pm.c52
-rw-r--r--arch/arm/mach-mx28/regs-clkctrl.h1
-rw-r--r--arch/arm/mach-mx28/sleep.S195
-rw-r--r--arch/arm/mach-mx28/usb_dr.c24
-rw-r--r--arch/arm/mach-mx3/devices.c17
-rw-r--r--arch/arm/mach-mx3/mx31ads.c20
-rw-r--r--arch/arm/mach-mx3/mx3_3stack.c44
-rw-r--r--arch/arm/mach-mx3/usb_dr.c22
-rw-r--r--arch/arm/mach-mx35/devices.c65
-rw-r--r--arch/arm/mach-mx35/mx35_3stack.c46
-rw-r--r--arch/arm/mach-mx35/usb_dr.c22
-rw-r--r--arch/arm/mach-mx37/cpu.c2
-rw-r--r--arch/arm/mach-mx37/crm_regs.h35
-rw-r--r--arch/arm/mach-mx37/devices.c51
-rw-r--r--arch/arm/mach-mx37/mx37_3stack.c44
-rw-r--r--arch/arm/mach-mx37/usb_dr.c23
-rw-r--r--arch/arm/mach-mx5/Kconfig267
-rw-r--r--arch/arm/mach-mx5/Makefile17
-rw-r--r--arch/arm/mach-mx5/Makefile.boot3
-rw-r--r--arch/arm/mach-mx5/board-ccwmx51.h77
-rw-r--r--arch/arm/mach-mx5/bus_freq.c582
-rw-r--r--arch/arm/mach-mx5/clock.c548
-rw-r--r--arch/arm/mach-mx5/cpu.c101
-rw-r--r--arch/arm/mach-mx5/crm_regs.h221
-rw-r--r--arch/arm/mach-mx5/devices.c521
-rw-r--r--arch/arm/mach-mx5/devices.h27
-rw-r--r--arch/arm/mach-mx5/devices_ccwmx51.c1019
-rw-r--r--arch/arm/mach-mx5/devices_ccwmx51.h14
-rw-r--r--arch/arm/mach-mx5/displays/displays.h27
-rw-r--r--arch/arm/mach-mx5/dma.c73
-rw-r--r--arch/arm/mach-mx5/dummy_gpio.c20
-rw-r--r--arch/arm/mach-mx5/iomux.c14
-rw-r--r--arch/arm/mach-mx5/lpmodes.c1
-rw-r--r--arch/arm/mach-mx5/mm.c4
-rw-r--r--arch/arm/mach-mx5/mx51_3stack.c160
-rw-r--r--arch/arm/mach-mx5/mx51_babbage.c839
-rw-r--r--arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c8
-rw-r--r--arch/arm/mach-mx5/mx51_ccwmx51js.c323
-rw-r--r--arch/arm/mach-mx5/mx51_ccwmx51js_gpio.c901
-rw-r--r--arch/arm/mach-mx5/mx53_evk.c1353
-rw-r--r--arch/arm/mach-mx5/mx53_evk_pmic_mc13892.c18
-rw-r--r--arch/arm/mach-mx5/pm.c81
-rw-r--r--arch/arm/mach-mx5/sdram_autogating.c5
-rw-r--r--arch/arm/mach-mx5/serial.c95
-rw-r--r--arch/arm/mach-mx5/serial.h83
-rw-r--r--arch/arm/mach-mx5/system.c118
-rw-r--r--arch/arm/mach-mx5/usb.h3
-rw-r--r--arch/arm/mach-mx5/usb_dr.c176
-rw-r--r--arch/arm/mach-mx5/usb_h1.c81
-rw-r--r--arch/arm/plat-mxc/clock.c21
-rw-r--r--arch/arm/plat-mxc/dptc.c78
-rw-r--r--arch/arm/plat-mxc/dvfs_core.c191
-rw-r--r--arch/arm/plat-mxc/dvfs_per.c126
-rw-r--r--arch/arm/plat-mxc/include/mach/arc_otg.h7
-rw-r--r--arch/arm/plat-mxc/include/mach/common.h1
-rw-r--r--arch/arm/plat-mxc/include/mach/fsl_usb.h11
-rw-r--r--arch/arm/plat-mxc/include/mach/hardware.h3
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-v3.h50
-rw-r--r--arch/arm/plat-mxc/include/mach/memory.h4
-rw-r--r--arch/arm/plat-mxc/include/mach/mmc.h3
-rw-r--r--arch/arm/plat-mxc/include/mach/mx37.h3
-rw-r--r--arch/arm/plat-mxc/include/mach/mx5x.h91
-rw-r--r--arch/arm/plat-mxc/include/mach/mxc.h68
-rw-r--r--arch/arm/plat-mxc/include/mach/mxc_dvfs.h54
-rw-r--r--arch/arm/plat-mxc/include/mach/system.h3
-rw-r--r--arch/arm/plat-mxc/iomux-v3.c45
-rw-r--r--arch/arm/plat-mxc/iram.c5
-rw-r--r--arch/arm/plat-mxc/pwm.c2
-rw-r--r--arch/arm/plat-mxc/usb_common.c56
-rw-r--r--arch/arm/plat-mxc/utmixc.c2
-rw-r--r--arch/arm/plat-mxs/Kconfig1
-rw-r--r--arch/arm/plat-mxs/Makefile2
-rw-r--r--arch/arm/plat-mxs/clock.c48
-rw-r--r--arch/arm/plat-mxs/cpufreq.c62
-rw-r--r--arch/arm/plat-mxs/device.c84
-rw-r--r--arch/arm/plat-mxs/dma-apbx.c3
-rw-r--r--arch/arm/plat-mxs/dmaengine.c14
-rw-r--r--arch/arm/plat-mxs/gpio.c2
-rw-r--r--arch/arm/plat-mxs/icoll.c6
-rw-r--r--arch/arm/plat-mxs/include/mach/bus_freq.h11
-rw-r--r--arch/arm/plat-mxs/include/mach/clock.h21
-rw-r--r--arch/arm/plat-mxs/include/mach/device.h62
-rw-r--r--arch/arm/plat-mxs/include/mach/dmaengine.h1
-rw-r--r--arch/arm/plat-mxs/include/mach/system.h1
-rw-r--r--arch/arm/plat-mxs/include/mach/timex.h2
-rw-r--r--arch/arm/plat-mxs/iram.c5
-rw-r--r--arch/arm/plat-mxs/timer-nomatch.c9
-rw-r--r--arch/arm/plat-mxs/usb_common.c21
-rw-r--r--arch/arm/plat-mxs/utmixc.c4
-rw-r--r--arch/arm/tools/mach-types11
-rw-r--r--block/genhd.c17
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/ata/Kconfig17
-rw-r--r--drivers/ata/Makefile3
-rw-r--r--drivers/ata/ahci.c2063
-rw-r--r--drivers/ata/libata-core.c36
-rw-r--r--drivers/ata/pata_fsl.c5
-rw-r--r--drivers/ata/pata_pcmcia.c2
-rw-r--r--drivers/char/Kconfig18
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/hw_random/fsl-rngc.c48
-rw-r--r--drivers/crypto/Kconfig2
-rw-r--r--drivers/crypto/dcp.c253
-rw-r--r--drivers/crypto/dcp.h7
-rw-r--r--drivers/dma/Kconfig9
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-mxs.c45
-rw-r--r--drivers/i2c/busses/i2c-mxs.h1
-rw-r--r--drivers/input/evdev.c29
-rw-r--r--drivers/input/keyboard/Makefile2
-rw-r--r--drivers/input/keyboard/mxc_keyb.c239
-rw-r--r--drivers/input/misc/mma7455l.c2
-rw-r--r--drivers/input/touchscreen/ads7846.c1157
-rw-r--r--drivers/input/touchscreen/mxc_ts.c58
-rw-r--r--drivers/leds/leds-mxs-pwm.c25
-rw-r--r--drivers/media/video/Kconfig11
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/mxc/capture/Kconfig18
-rw-r--r--drivers/media/video/mxc/capture/Makefile2
-rw-r--r--drivers/media/video/mxc/capture/adv7180.c67
-rw-r--r--drivers/media/video/mxc/capture/csi_v4l2_capture.c12
-rw-r--r--drivers/media/video/mxc/capture/emma_v4l2_capture.c17
-rw-r--r--drivers/media/video/mxc/capture/ipu_csi_enc.c69
-rw-r--r--drivers/media/video/mxc/capture/ipu_prp_enc.c11
-rw-r--r--drivers/media/video/mxc/capture/ipu_prp_vf_sdc_bg.c2
-rw-r--r--drivers/media/video/mxc/capture/ipu_still.c65
-rw-r--r--drivers/media/video/mxc/capture/mt9v111.c1085
-rw-r--r--drivers/media/video/mxc/capture/mt9v111.h8
-rw-r--r--drivers/media/video/mxc/capture/mx27_prpsw.c4
-rw-r--r--drivers/media/video/mxc/capture/mxc_v4l2_capture.c565
-rw-r--r--drivers/media/video/mxc/capture/mxc_v4l2_capture.h6
-rw-r--r--drivers/media/video/mxc/capture/ov3640.c87
-rw-r--r--drivers/media/video/mxc/output/Makefile3
-rw-r--r--drivers/media/video/mxc/output/mxc_v4l2_output.c1241
-rw-r--r--drivers/media/video/mxc/output/mxc_v4l2_output.h12
-rw-r--r--drivers/media/video/mxs_pxp.c8
-rw-r--r--drivers/media/video/uvc/uvc_video.c4
-rw-r--r--drivers/media/video/videobuf-dma-contig.c2
-rw-r--r--drivers/misc/Kconfig12
-rw-r--r--drivers/misc/Makefile3
-rw-r--r--drivers/mmc/core/Kconfig4
-rw-r--r--drivers/mmc/core/core.c405
-rw-r--r--drivers/mmc/core/core.h10
-rw-r--r--drivers/mmc/core/host.c6
-rw-r--r--drivers/mmc/core/host.h2
-rw-r--r--drivers/mmc/core/mmc.c407
-rw-r--r--drivers/mmc/core/mmc_ops.c36
-rw-r--r--drivers/mmc/core/mmc_ops.h1
-rw-r--r--drivers/mmc/core/sd.c52
-rw-r--r--drivers/mmc/core/sdio.c196
-rw-r--r--drivers/mmc/core/sdio_io.c49
-rw-r--r--drivers/mmc/core/sdio_ops.c112
-rw-r--r--drivers/mmc/core/sdio_ops.h1
-rw-r--r--drivers/mmc/host/mx_sdhci.c127
-rw-r--r--drivers/mmc/host/mx_sdhci.h17
-rw-r--r--drivers/mmc/host/mxc_mmc.c4
-rw-r--r--drivers/mmc/host/mxs-mmc.c92
-rw-r--r--drivers/mtd/devices/mxc_dataflash.c4
-rw-r--r--drivers/mtd/nand/Kconfig46
-rw-r--r--drivers/mtd/nand/Makefile4
-rw-r--r--drivers/mtd/nand/mxc_nd2.c292
-rw-r--r--drivers/mtd/nand/mxc_nd2.h85
-rw-r--r--drivers/mtd/nand/nand_device_info.c8
-rw-r--r--drivers/mxc/Kconfig1
-rw-r--r--drivers/mxc/Makefile1
-rw-r--r--drivers/mxc/ipu/ipu_common.c32
-rw-r--r--drivers/mxc/ipu/ipu_csi.c9
-rw-r--r--drivers/mxc/ipu/ipu_device.c1
-rw-r--r--drivers/mxc/ipu/ipu_ic.c6
-rw-r--r--drivers/mxc/ipu/pf/mxc_pf.c1
-rw-r--r--drivers/mxc/ipu3/ipu_calc_stripes_sizes.c2
-rw-r--r--drivers/mxc/ipu3/ipu_capture.c130
-rw-r--r--drivers/mxc/ipu3/ipu_common.c184
-rw-r--r--drivers/mxc/ipu3/ipu_device.c25
-rw-r--r--drivers/mxc/ipu3/ipu_disp.c364
-rw-r--r--drivers/mxc/ipu3/ipu_ic.c39
-rw-r--r--drivers/mxc/ipu3/ipu_param_mem.h55
-rw-r--r--drivers/mxc/ipu3/ipu_prv.h4
-rw-r--r--drivers/mxc/ipu3/ipu_regs.h11
-rw-r--r--drivers/mxc/mlb/Kconfig2
-rw-r--r--drivers/mxc/pmic/core/mc13892.c3
-rw-r--r--drivers/mxc/pmic/core/pmic.h5
-rw-r--r--drivers/mxc/pmic/mc13892/pmic_adc.c321
-rw-r--r--drivers/mxc/pmic/mc13892/pmic_battery.c59
-rw-r--r--drivers/mxc/security/Kconfig1
-rw-r--r--drivers/mxc/security/sahara2/fsl_shw_auth.c4
-rw-r--r--drivers/mxc/security/scc2_driver.c2
-rw-r--r--drivers/mxc/vpu/mxc_vpu.c47
-rw-r--r--drivers/net/Kconfig7
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/can/Kconfig4
-rw-r--r--drivers/net/can/flexcan/dev.c112
-rw-r--r--drivers/net/can/flexcan/flexcan.h31
-rw-r--r--drivers/net/can/flexcan/mbm.c74
-rw-r--r--drivers/net/enc28j60.c18
-rw-r--r--drivers/net/fec.c62
-rw-r--r--drivers/net/fec_1588.c155
-rw-r--r--drivers/net/fec_1588.h51
-rw-r--r--drivers/net/phy/mdio_bus.c72
-rw-r--r--drivers/net/phy/phy.c4
-rw-r--r--drivers/net/phy/phy_device.c31
-rw-r--r--drivers/net/smsc911x.c5
-rw-r--r--drivers/net/wireless/ath6kl/os/linux/ar6000_android.c2
-rw-r--r--drivers/power/mxs/Makefile2
-rw-r--r--drivers/power/mxs/ddi_bc_internal.h3
-rw-r--r--drivers/power/mxs/ddi_power_battery.c4
-rw-r--r--drivers/power/mxs/fiq.S6
-rw-r--r--drivers/power/mxs/linux.c19
-rw-r--r--drivers/regulator/Kconfig5
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/rtc/Kconfig10
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-mxc_v2.c104
-rw-r--r--drivers/rtc/rtc-mxs.c2
-rw-r--r--drivers/serial/Kconfig18
-rw-r--r--drivers/serial/mxs-auart.c193
-rw-r--r--drivers/serial/mxs-duart.c31
-rw-r--r--drivers/spi/Kconfig5
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/mxc_spi.c38
-rw-r--r--drivers/staging/android/binder.c10
-rw-r--r--drivers/staging/android/logger.c7
-rw-r--r--drivers/staging/android/logger.h1
-rw-r--r--drivers/staging/android/lowmemorykiller.c51
-rw-r--r--drivers/uio/uio_pdrv_genirq.c6
-rw-r--r--drivers/usb/class/cdc-acm.c2
-rw-r--r--drivers/usb/core/driver.c5
-rw-r--r--drivers/usb/core/generic.c27
-rw-r--r--drivers/usb/core/hcd.c27
-rw-r--r--drivers/usb/core/hub.c14
-rw-r--r--drivers/usb/gadget/Kconfig10
-rw-r--r--drivers/usb/gadget/Makefile2
-rw-r--r--drivers/usb/gadget/arcotg_udc.c514
-rw-r--r--drivers/usb/gadget/arcotg_udc.h12
-rw-r--r--drivers/usb/gadget/composite.c39
-rw-r--r--drivers/usb/gadget/f_acm.c9
-rw-r--r--drivers/usb/gadget/file_storage.c9
-rw-r--r--drivers/usb/gadget/fsl_updater.c79
-rw-r--r--drivers/usb/gadget/fsl_updater.h1
-rw-r--r--drivers/usb/host/ehci-arc.c280
-rw-r--r--drivers/usb/host/ehci-hub.c1
-rw-r--r--drivers/usb/otg/fsl_otg.c233
-rw-r--r--drivers/video/modedb.c5
-rw-r--r--drivers/video/mxc/Kconfig51
-rw-r--r--drivers/video/mxc/Makefile6
-rwxr-xr-xdrivers/video/mxc/ccwmx51_display.c78
-rw-r--r--drivers/video/mxc/mxc_ipuv3_fb.c510
-rw-r--r--drivers/video/mxc/mxcfb_claa_wvga.c12
-rw-r--r--drivers/video/mxc/tve.c140
-rw-r--r--drivers/video/mxs/Kconfig6
-rw-r--r--drivers/video/mxs/Makefile2
-rw-r--r--drivers/watchdog/mxc_wdt.c2
-rw-r--r--firmware/Makefile2
-rw-r--r--fs/fat/dir.c9
-rw-r--r--fs/fat/fat.h1
-rw-r--r--fs/partitions/check.c9
-rw-r--r--fs/proc/base.c35
-rw-r--r--fs/proc/task_mmu.c3
-rw-r--r--include/linux/Kbuild2
-rw-r--r--include/linux/ata.h4
-rw-r--r--include/linux/fec.h21
-rw-r--r--include/linux/fsl_devices.h2
-rw-r--r--include/linux/ipu.h21
-rw-r--r--include/linux/libata.h2
-rw-r--r--include/linux/mm.h1
-rw-r--r--include/linux/mmc/card.h8
-rw-r--r--include/linux/mmc/core.h1
-rw-r--r--include/linux/mmc/host.h68
-rw-r--r--include/linux/mmc/mmc.h32
-rw-r--r--include/linux/mmc/sdio_func.h5
-rw-r--r--include/linux/msdos_fs.h12
-rw-r--r--include/linux/mxcfb.h74
-rw-r--r--include/linux/phy.h2
-rw-r--r--include/linux/sched.h3
-rw-r--r--include/linux/sockios.h1
-rw-r--r--include/linux/spi/ads7846.h36
-rw-r--r--include/linux/usb/composite.h1
-rw-r--r--include/media/v4l2-int-device.h4
-rw-r--r--include/net/bluetooth/hci.h6
-rw-r--r--include/net/bluetooth/hci_core.h7
-rw-r--r--include/net/bluetooth/sco.h4
-rw-r--r--include/net/tcp.h2
-rw-r--r--init/Kconfig9
-rw-r--r--kernel/fork.c16
-rw-r--r--kernel/irq/handle.c4
-rw-r--r--kernel/power/Kconfig67
-rw-r--r--kernel/power/Makefile5
-rw-r--r--kernel/power/main.c20
-rw-r--r--kernel/power/power.h24
-rw-r--r--kernel/power/process.c25
-rw-r--r--kernel/power/suspend.c3
-rw-r--r--mm/Makefile1
-rw-r--r--mm/shmem.c13
-rw-r--r--net/bluetooth/hci_conn.c33
-rw-r--r--net/bluetooth/hci_event.c6
-rw-r--r--net/bluetooth/l2cap.c5
-rw-r--r--net/bluetooth/rfcomm/core.c13
-rw-r--r--net/bluetooth/sco.c54
-rw-r--r--net/core/dev.c10
-rw-r--r--net/ipv4/af_inet.c2
-rw-r--r--net/ipv4/devinet.c9
-rw-r--r--net/ipv4/tcp_ipv4.c44
-rw-r--r--net/rfkill/core.c6
-rw-r--r--net/socket.c18
-rw-r--r--sound/arm/mxc-alsa-spdif.c18
-rw-r--r--sound/soc/codecs/Kconfig4
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/mxs-adc-codec.c237
-rw-r--r--sound/soc/codecs/sgtl5000.c49
-rw-r--r--sound/soc/codecs/wm8753.c14
-rw-r--r--sound/soc/codecs/wm8753.h1
-rw-r--r--sound/soc/imx/Kconfig10
-rw-r--r--sound/soc/imx/Makefile3
-rw-r--r--sound/soc/imx/imx-3stack-ak4647.c3
-rw-r--r--sound/soc/imx/imx-3stack-ak5702.c4
-rw-r--r--sound/soc/imx/imx-3stack-wm8580.c10
-rw-r--r--sound/soc/imx/imx-ccwmx51-wm8753.c38
-rw-r--r--sound/soc/imx/imx-esai.c353
-rw-r--r--sound/soc/imx/imx-esai.h286
-rw-r--r--sound/soc/imx/imx-pcm.c8
-rw-r--r--sound/soc/mxs/mxs-adc.c246
-rw-r--r--sound/soc/mxs/mxs-dai.c1
-rw-r--r--sound/soc/mxs/mxs-evk-adc.c107
-rw-r--r--sound/soc/mxs/mxs-pcm.c4
361 files changed, 20865 insertions, 9231 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 3f1b470beacf..7f161d76e5d2 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1502,6 +1502,8 @@ source "drivers/accessibility/Kconfig"
source "drivers/leds/Kconfig"
+source "drivers/switch/Kconfig"
+
source "drivers/rtc/Kconfig"
source "drivers/dma/Kconfig"
diff --git a/arch/arm/configs/imx23evk_defconfig b/arch/arm/configs/imx23evk_defconfig
index 31a22aa4c274..d65c1fbdd21b 100644
--- a/arch/arm/configs/imx23evk_defconfig
+++ b/arch/arm/configs/imx23evk_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.31
-# Tue Apr 13 15:44:41 2010
+# Mon May 24 17:09:02 2010
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -20,6 +20,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_ZONE_DMA=y
+CONFIG_FIQ=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -184,6 +185,7 @@ CONFIG_ARCH_MXS=y
# CONFIG_ARCH_OMAP is not set
CONFIG_IRAM_ALLOC=y
CONFIG_DMA_ZONE_SIZE=12
+CONFIG_VECTORS_PHY_ADDR=0
#
# Freescale i.MXS implementations
@@ -191,6 +193,8 @@ CONFIG_DMA_ZONE_SIZE=12
# CONFIG_ARCH_MX28 is not set
CONFIG_ARCH_MX23=y
CONFIG_MACH_MX23EVK=y
+CONFIG_MXS_UNIQUE_ID=y
+CONFIG_MXS_UNIQUE_ID_OTP=y
CONFIG_MXS_ICOLL=y
CONFIG_MXS_EARLY_CONSOLE=y
CONFIG_MXS_DMA_ENGINE=y
@@ -345,7 +349,8 @@ CONFIG_NET=y
#
# Networking options
#
-# CONFIG_PACKET is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
@@ -357,7 +362,10 @@ CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
-# CONFIG_IP_PNP is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
@@ -456,8 +464,9 @@ CONFIG_NETFILTER_ADVANCED=y
# CONFIG_AF_RXRPC is not set
CONFIG_WIRELESS=y
# CONFIG_CFG80211 is not set
-# CONFIG_WIRELESS_OLD_REGULATORY is not set
-# CONFIG_WIRELESS_EXT is not set
+CONFIG_WIRELESS_OLD_REGULATORY=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
# CONFIG_LIB80211 is not set
#
@@ -465,7 +474,8 @@ CONFIG_WIRELESS=y
#
CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
-# CONFIG_RFKILL is not set
+CONFIG_RFKILL=y
+CONFIG_RFKILL_INPUT=y
# CONFIG_NET_9P is not set
#
@@ -485,16 +495,112 @@ CONFIG_EXTRA_FIRMWARE=""
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
# CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_MXC_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_GPMI_NFC=y
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+CONFIG_MTD_UBI_GLUEBI=y
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+CONFIG_MTD_UBI_BLOCK=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_UB is not set
CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_COUNT=4
+CONFIG_BLK_DEV_RAM_SIZE=16384
# CONFIG_BLK_DEV_XIP is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -510,6 +616,7 @@ CONFIG_MXS_PERSISTENT=y
# EEPROM support
#
# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
# CONFIG_EEPROM_LEGACY is not set
# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
@@ -567,6 +674,8 @@ CONFIG_NET_ETHERNET=y
# CONFIG_AX88796 is not set
# CONFIG_SMC91X is not set
# CONFIG_DM9000 is not set
+CONFIG_ENC28J60=y
+# CONFIG_ENC28J60_WRITEVERIFY is not set
# CONFIG_ETHOC is not set
# CONFIG_SMC911X is not set
# CONFIG_SMSC911X is not set
@@ -580,6 +689,7 @@ CONFIG_NET_ETHERNET=y
# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
# CONFIG_B44 is not set
# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
CONFIG_NETDEV_1000=y
CONFIG_NETDEV_10000=y
@@ -601,6 +711,7 @@ CONFIG_NETDEV_10000=y
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
# CONFIG_USB_USBNET is not set
+# CONFIG_USB_HSO is not set
# CONFIG_WAN is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
@@ -644,7 +755,10 @@ CONFIG_KEYBOARD_MXS=y
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
# CONFIG_TOUCHSCREEN_AD7879 is not set
# CONFIG_TOUCHSCREEN_EETI is not set
# CONFIG_TOUCHSCREEN_FUJITSU is not set
@@ -704,6 +818,7 @@ CONFIG_MXS_VIIM=y
CONFIG_SERIAL_MXS_DUART=y
CONFIG_SERIAL_MXS_AUART=y
CONFIG_SERIAL_MXS_DUART_CONSOLE=y
+# CONFIG_SERIAL_MAX3100 is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
@@ -760,7 +875,22 @@ CONFIG_I2C_MXS_SELECT0=y
# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_I2C_DEBUG_CHIP is not set
# CONFIG_I2C_SLAVE is not set
-# CONFIG_SPI is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_MXS=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
# CONFIG_DEBUG_GPIO is not set
@@ -784,6 +914,8 @@ CONFIG_GPIOLIB=y
#
# SPI GPIO expanders:
#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
# CONFIG_W1 is not set
CONFIG_POWER_SUPPLY=y
# CONFIG_POWER_SUPPLY_DEBUG is not set
@@ -798,6 +930,7 @@ CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_AD7414 is not set
# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
# CONFIG_SENSORS_ADM1021 is not set
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
@@ -818,6 +951,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_GL520SM is not set
# CONFIG_SENSORS_IT87 is not set
# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
# CONFIG_SENSORS_LM75 is not set
# CONFIG_SENSORS_LM77 is not set
# CONFIG_SENSORS_LM78 is not set
@@ -831,6 +965,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LTC4215 is not set
# CONFIG_SENSORS_LTC4245 is not set
# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_MAX6650 is not set
# CONFIG_SENSORS_PC87360 is not set
@@ -853,6 +988,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_W83L786NG is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
CONFIG_MXC_MMA7450=m
# CONFIG_THERMAL is not set
@@ -896,6 +1032,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_PCF50633 is not set
# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
CONFIG_MEDIA_SUPPORT=y
#
@@ -1028,6 +1165,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_MXS=y
# CONFIG_FB_MXS_LCD_43WVF1G is not set
CONFIG_FB_MXS_LCD_LMS430=y
+# CONFIG_FB_MXS_TVENC is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FB_METRONOME is not set
@@ -1081,6 +1219,7 @@ CONFIG_SND_VERBOSE_PROCFS=y
# CONFIG_SND_EMU10K1_SEQ is not set
# CONFIG_SND_DRIVERS is not set
# CONFIG_SND_ARM is not set
+CONFIG_SND_SPI=y
# CONFIG_SND_USB is not set
CONFIG_SND_SOC=y
CONFIG_SND_MXS_SOC=y
@@ -1264,6 +1403,7 @@ CONFIG_MMC_BLOCK_BOUNCE=y
# MMC/SD/SDIO Host Controller Drivers
#
# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_SPI is not set
# CONFIG_MMC_IMX_ESDHCI_PIO_MODE is not set
CONFIG_MMC_MXS=y
# CONFIG_MEMSTICK is not set
@@ -1305,6 +1445,13 @@ CONFIG_RTC_INTF_DEV=y
#
# SPI RTC drivers
#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
#
# Platform RTC drivers
@@ -1413,6 +1560,13 @@ CONFIG_MISC_FILESYSTEMS=y
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
# CONFIG_CRAMFS is not set
# CONFIG_SQUASHFS is not set
# CONFIG_VXFS_FS is not set
@@ -1425,8 +1579,18 @@ CONFIG_MISC_FILESYSTEMS=y
# CONFIG_UFS_FS is not set
# CONFIG_NILFS2_FS is not set
CONFIG_NETWORK_FILESYSTEMS=y
-# CONFIG_NFS_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
@@ -1436,8 +1600,24 @@ CONFIG_NETWORK_FILESYSTEMS=y
#
# Partition Types
#
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=y
@@ -1518,7 +1698,7 @@ CONFIG_DEBUG_PREEMPT=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_WRITECOUNT is not set
# CONFIG_DEBUG_MEMORY_INIT is not set
diff --git a/arch/arm/configs/imx28evk_defconfig b/arch/arm/configs/imx28evk_defconfig
index 44cfd4dc0f06..9d3b1c98d198 100644
--- a/arch/arm/configs/imx28evk_defconfig
+++ b/arch/arm/configs/imx28evk_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.31
-# Tue Mar 23 23:51:39 2010
+# Tue Aug 3 11:34:57 2010
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -195,6 +195,7 @@ CONFIG_ARCH_MXS=y
# CONFIG_ARCH_OMAP is not set
CONFIG_IRAM_ALLOC=y
CONFIG_DMA_ZONE_SIZE=16
+CONFIG_VECTORS_PHY_ADDR=0
#
# Freescale i.MXS implementations
@@ -225,6 +226,8 @@ CONFIG_MXS_AUART3_DEVICE_ENABLE=y
CONFIG_MXS_AUART4_DEVICE_ENABLE=y
# CONFIG_MXS_AUART4_DMA_ENABLE is not set
CONFIG_MXS_RAM_FREQ_SCALING=y
+# CONFIG_MXS_RAM_MDDR is not set
+# CONFIG_MXS_RAM_DDR is not set
#
# Processor Type
@@ -438,9 +441,20 @@ CONFIG_CAN_FLEXCAN=m
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
-# CONFIG_WIRELESS is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_OLD_REGULATORY=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
# CONFIG_WIMAX is not set
-# CONFIG_RFKILL is not set
+CONFIG_RFKILL=y
+CONFIG_RFKILL_INPUT=y
# CONFIG_NET_9P is not set
#
@@ -460,11 +474,11 @@ CONFIG_EXTRA_FIRMWARE=""
# CONFIG_CONNECTOR is not set
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
# CONFIG_MTD_AFS_PARTS is not set
# CONFIG_MTD_AR7_PARTS is not set
@@ -528,7 +542,7 @@ CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
-CONFIG_MTD_NAND_GPMI1=y
+CONFIG_MTD_NAND_GPMI_NFC=y
# CONFIG_MTD_NAND_PLATFORM is not set
# CONFIG_MTD_ALAUDA is not set
# CONFIG_MTD_ONENAND is not set
@@ -550,16 +564,17 @@ CONFIG_MTD_UBI_BEB_RESERVE=1
# UBI debugging options
#
# CONFIG_MTD_UBI_DEBUG is not set
-# CONFIG_MTD_UBI_BLOCK is not set
+CONFIG_MTD_UBI_BLOCK=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_UB is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=4
-CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_SIZE=16384
# CONFIG_BLK_DEV_XIP is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -568,6 +583,7 @@ CONFIG_MISC_DEVICES=y
# CONFIG_ICS932S401 is not set
# CONFIG_ENCLOSURE_SERVICES is not set
# CONFIG_ISL29003 is not set
+CONFIG_MXS_PERSISTENT=y
# CONFIG_C2PORT is not set
#
@@ -669,6 +685,7 @@ CONFIG_MII=y
# CONFIG_B44 is not set
# CONFIG_KS8842 is not set
CONFIG_FEC=y
+# CONFIG_FEC_1588 is not set
# CONFIG_FEC2 is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
@@ -691,6 +708,7 @@ CONFIG_FEC=y
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
# CONFIG_USB_USBNET is not set
+# CONFIG_USB_HSO is not set
# CONFIG_WAN is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
@@ -833,6 +851,7 @@ CONFIG_MXS_VIIM=y
#
CONFIG_SERIAL_MXS_DUART=y
CONFIG_SERIAL_MXS_AUART=y
+# CONFIG_SERIAL_MXS_AUART_CONSOLE is not set
CONFIG_SERIAL_MXS_DUART_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
@@ -931,6 +950,7 @@ CONFIG_POWER_SUPPLY=y
# CONFIG_BATTERY_BQ27x00 is not set
# CONFIG_BATTERY_MAX17040 is not set
CONFIG_BATTERY_MXS=y
+# CONFIG_MXS_VBUS_CURRENT_DRAW is not set
# CONFIG_HWMON is not set
# CONFIG_THERMAL is not set
# CONFIG_THERMAL_HWMON is not set
@@ -1117,6 +1137,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_MXS=y
CONFIG_FB_MXS_LCD_43WVF1G=y
# CONFIG_FB_MXS_LCD_LMS430 is not set
+# CONFIG_FB_MXS_TVENC is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FB_METRONOME is not set
@@ -1175,8 +1196,6 @@ CONFIG_SND_MXS_SOC=y
CONFIG_SND_MXS_SOC_SPDIF_DAI=y
CONFIG_SND_MXS_SOC_EVK_DEVB=y
CONFIG_SND_MXS_SOC_DAI=y
-CONFIG_SND_MXS_SOC_SAIF0_SELECT=y
-# CONFIG_SND_MXS_SOC_SAIF1_SELECT is not set
CONFIG_SND_MXS_SOC_EVK_DEVB_SPDIF=y
CONFIG_SND_SOC_I2C_AND_SPI=y
# CONFIG_SND_SOC_ALL_CODECS is not set
@@ -1237,16 +1256,18 @@ CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_EHCI=y
CONFIG_USB=y
# CONFIG_USB_DEBUG is not set
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
#
# Miscellaneous USB options
#
# CONFIG_USB_DEVICEFS is not set
# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_DYNAMIC_MINORS=y
-# CONFIG_USB_SUSPEND is not set
-# CONFIG_USB_OTG is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
# CONFIG_USB_MON is not set
# CONFIG_USB_WUSB is not set
# CONFIG_USB_WUSB_CBAF is not set
@@ -1255,7 +1276,7 @@ CONFIG_USB_DYNAMIC_MINORS=y
# USB Host Controller Drivers
#
# CONFIG_USB_C67X00_HCD is not set
-CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ARC=y
CONFIG_USB_EHCI_ARC_H1=y
CONFIG_USB_EHCI_ARC_OTG=y
@@ -1340,7 +1361,7 @@ CONFIG_USB_STORAGE=y
# CONFIG_USB_TEST is not set
# CONFIG_USB_ISIGHTFW is not set
# CONFIG_USB_VST is not set
-CONFIG_USB_GADGET=m
+CONFIG_USB_GADGET=y
# CONFIG_USB_GADGET_DEBUG_FILES is not set
# CONFIG_USB_GADGET_DEBUG_FS is not set
CONFIG_USB_GADGET_VBUS_DRAW=2
@@ -1362,7 +1383,7 @@ CONFIG_USB_GADGET_SELECTED=y
# CONFIG_USB_GADGET_NET2280 is not set
# CONFIG_USB_GADGET_GOKU is not set
CONFIG_USB_GADGET_ARC=y
-CONFIG_USB_ARC=m
+CONFIG_USB_ARC=y
CONFIG_WORKAROUND_ARCUSB_REG_RW=y
# CONFIG_USB_GADGET_LANGWELL is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
@@ -1386,7 +1407,7 @@ CONFIG_USB_G_SERIAL=m
CONFIG_USB_OTG_UTILS=y
# CONFIG_USB_GPIO_VBUS is not set
# CONFIG_NOP_USB_XCEIV is not set
-# CONFIG_MXC_OTG is not set
+CONFIG_MXC_OTG=y
CONFIG_MMC=y
# CONFIG_MMC_DEBUG is not set
CONFIG_MMC_UNSAFE_RESUME=y
@@ -1485,6 +1506,7 @@ CONFIG_DMADEVICES=y
#
# DMA Devices
#
+# CONFIG_MXC_PXP is not set
# CONFIG_AUXDISPLAY is not set
CONFIG_REGULATOR=y
# CONFIG_REGULATOR_DEBUG is not set
@@ -1495,6 +1517,7 @@ CONFIG_REGULATOR=y
# CONFIG_REGULATOR_MAX1586 is not set
# CONFIG_REGULATOR_LP3971 is not set
CONFIG_REGULATOR_MXS=y
+# CONFIG_REGULATOR_MAX17135 is not set
# CONFIG_UIO is not set
# CONFIG_STAGING is not set
@@ -1506,13 +1529,13 @@ CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT2_FS_SECURITY=y
# CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=m
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT3_FS_SECURITY=y
# CONFIG_EXT4_FS is not set
-CONFIG_JBD=m
+CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
diff --git a/arch/arm/configs/imx28evk_updater_defconfig b/arch/arm/configs/imx28evk_updater_defconfig
index f2ced40e1b14..fe9a908e7e62 100644
--- a/arch/arm/configs/imx28evk_updater_defconfig
+++ b/arch/arm/configs/imx28evk_updater_defconfig
@@ -1,7 +1,6 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.31
-# Fri Apr 9 13:26:15 2010
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -180,6 +179,7 @@ CONFIG_ARCH_MXS=y
# CONFIG_ARCH_OMAP is not set
CONFIG_IRAM_ALLOC=y
CONFIG_DMA_ZONE_SIZE=16
+CONFIG_VECTORS_PHY_ADDR=0
#
# Freescale i.MXS implementations
@@ -210,6 +210,8 @@ CONFIG_MXS_AUART_PORTS=5
# CONFIG_MXS_AUART4_DEVICE_ENABLE is not set
# CONFIG_MXS_AUART4_DMA_ENABLE is not set
CONFIG_MXS_RAM_FREQ_SCALING=y
+# CONFIG_MXS_RAM_MDDR is not set
+# CONFIG_MXS_RAM_DDR is not set
#
# Processor Type
@@ -289,6 +291,21 @@ CONFIG_CMDLINE="console=ttyAM0,115200 rdinit=/linuxrc"
#
# CPU Power Management
#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
# CONFIG_CPU_IDLE is not set
#
@@ -337,9 +354,107 @@ CONFIG_FW_LOADER=y
CONFIG_FIRMWARE_IN_KERNEL=y
CONFIG_EXTRA_FIRMWARE=""
# CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_GPMI_NFC=y
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_MTD_UBI_BLOCK is not set
# CONFIG_PARPORT is not set
-# CONFIG_BLK_DEV is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_MG_DISK is not set
# CONFIG_MISC_DEVICES is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
@@ -391,6 +506,7 @@ CONFIG_INPUT=y
# CONFIG_VT is not set
# CONFIG_DEVKMEM is not set
# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_MXS_VIIM is not set
#
# Serial drivers
@@ -415,6 +531,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_I2C is not set
# CONFIG_I2C_SLAVE is not set
# CONFIG_SPI is not set
+CONFIG_FSL_OTP=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_GPIOLIB=y
# CONFIG_GPIO_SYSFS is not set
@@ -467,6 +584,7 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
# CONFIG_FB is not set
+# CONFIG_FB_MXS_TVENC is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
@@ -649,15 +767,15 @@ CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT2_FS_SECURITY=y
# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
CONFIG_EXT4_FS=y
-# CONFIG_EXT4DEV_COMPAT is not set
+CONFIG_EXT4DEV_COMPAT=y
CONFIG_EXT4_FS_XATTR=y
-# CONFIG_EXT4_FS_POSIX_ACL is not set
-# CONFIG_EXT4_FS_SECURITY is not set
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
CONFIG_JBD=y
CONFIG_JBD2=y
CONFIG_FS_MBCACHE=y
@@ -706,7 +824,32 @@ CONFIG_TMPFS=y
# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
# CONFIG_CONFIGFS_FS is not set
-# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
#
# Partition Types
@@ -787,7 +930,96 @@ CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_SECURITY is not set
# CONFIG_SECURITYFS is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
-# CONFIG_CRYPTO is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_CRYPTODEV is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_DCP is not set
# CONFIG_BINARY_PRINTF is not set
#
@@ -803,6 +1035,9 @@ CONFIG_CRC32=y
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
CONFIG_DECOMPRESS_GZIP=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_HAS_IOMEM=y
diff --git a/arch/arm/configs/imx35_3stack_defconfig b/arch/arm/configs/imx35_3stack_defconfig
index 308c94789192..733771b53ced 100644
--- a/arch/arm/configs/imx35_3stack_defconfig
+++ b/arch/arm/configs/imx35_3stack_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.31
-# Sat Dec 5 22:30:18 2009
+# Wed Jul 14 14:01:59 2010
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -152,6 +152,7 @@ CONFIG_FREEZER=y
# CONFIG_ARCH_FOOTBRIDGE is not set
CONFIG_ARCH_MXC=y
# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_MXS is not set
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
# CONFIG_ARCH_IOP13XX is not set
@@ -181,6 +182,7 @@ CONFIG_ARCH_MXC=y
# CONFIG_ARCH_U300 is not set
# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_OMAP is not set
+CONFIG_IRAM_ALLOC=y
CONFIG_DMA_ZONE_SIZE=24
CONFIG_UTMI_MXC=y
@@ -193,10 +195,9 @@ CONFIG_UTMI_MXC=y
# CONFIG_ARCH_MX25 is not set
CONFIG_ARCH_MX35=y
# CONFIG_ARCH_MX37 is not set
-# CONFIG_ARCH_MX51 is not set
+# CONFIG_ARCH_MX5 is not set
CONFIG_MXC_SDMA_API=y
CONFIG_SDMA_IRAM=y
-CONFIG_SDMA_IRAM_SIZE=0x1000
CONFIG_ARCH_MXC_HAS_NFC_V2=y
CONFIG_I2C_MXC_SELECT1=y
# CONFIG_I2C_MXC_SELECT2 is not set
@@ -213,14 +214,11 @@ CONFIG_MACH_MX35_3DS=y
# CONFIG_MX35_DOZE_DURING_IDLE is not set
#
-# SDMA options
-#
-
-#
# Device options
#
CONFIG_MXC_PSEUDO_IRQS=y
CONFIG_ARCH_HAS_EVTMON=y
+CONFIG_ISP1504_MXC=y
# CONFIG_MXC_IRQ_PRIOR is not set
# CONFIG_MXC_PWM is not set
CONFIG_ARCH_HAS_RNGC=y
@@ -540,7 +538,6 @@ CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
-# CONFIG_MTD_NAND_IMX_NFC is not set
CONFIG_MTD_NAND_MXC_V2=y
# CONFIG_MTD_NAND_MXC_SWECC is not set
# CONFIG_MTD_NAND_MXC_FORCE_CE is not set
@@ -630,6 +627,7 @@ CONFIG_SCSI_LOWLEVEL=y
CONFIG_ATA=m
# CONFIG_ATA_NONSTANDARD is not set
# CONFIG_SATA_PMP is not set
+# CONFIG_SATA_AHCI_PLATFORM is not set
CONFIG_ATA_SFF=y
# CONFIG_SATA_MV is not set
# CONFIG_PATA_PLATFORM is not set
@@ -1273,6 +1271,7 @@ CONFIG_SND_SOC_IMX_3STACK_AK4647=y
CONFIG_SND_SOC_IMX_3STACK_WM8580=y
# CONFIG_SND_SOC_IMX_3STACK_AK5702 is not set
CONFIG_SND_SOC_IMX_3STACK_BLUETOOTH=y
+# CONFIG_SND_SOC_IMX_3STACK_CS42888 is not set
CONFIG_SND_SOC_I2C_AND_SPI=y
# CONFIG_SND_SOC_ALL_CODECS is not set
CONFIG_SND_SOC_WM8580=y
@@ -1465,17 +1464,13 @@ CONFIG_USB_ARC=m
# CONFIG_USB_GADGET_LANGWELL is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
CONFIG_USB_GADGET_DUALSPEED=y
-CONFIG_USB_GADGET_ARC_OTG=y
-# CONFIG_USB_GADGET_FSL_MC13783 is not set
-# CONFIG_USB_GADGET_FSL_1301 is not set
-# CONFIG_USB_GADGET_FSL_1504 is not set
-CONFIG_USB_GADGET_FSL_UTMI=y
# CONFIG_USB_ZERO is not set
# CONFIG_USB_AUDIO is not set
CONFIG_USB_ETH=m
CONFIG_USB_ETH_RNDIS=y
CONFIG_USB_GADGETFS=m
CONFIG_USB_FILE_STORAGE=m
+# CONFIG_FSL_UTP is not set
# CONFIG_USB_FILE_STORAGE_TEST is not set
CONFIG_USB_G_SERIAL=m
# CONFIG_USB_MIDI_GADGET is not set
@@ -1485,8 +1480,10 @@ CONFIG_USB_G_SERIAL=m
#
# OTG and related infrastructure
#
+CONFIG_USB_OTG_UTILS=y
# CONFIG_USB_GPIO_VBUS is not set
# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_MXC_OTG is not set
CONFIG_MMC=y
# CONFIG_MMC_DEBUG is not set
CONFIG_MMC_UNSAFE_RESUME=y
@@ -1589,6 +1586,7 @@ CONFIG_REGULATOR=y
# CONFIG_REGULATOR_LP3971 is not set
CONFIG_REGULATOR_MC13892=y
CONFIG_REGULATOR_MC9S08DZ60=y
+# CONFIG_REGULATOR_MAX17135 is not set
# CONFIG_UIO is not set
# CONFIG_STAGING is not set
@@ -1682,6 +1680,11 @@ CONFIG_MXC_MLB=m
# CONFIG_IMX_ADC is not set
#
+# MXC GPU support
+#
+CONFIG_MXC_AMD_GPU=m
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1980,6 +1983,7 @@ CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
+CONFIG_GENERIC_ALLOCATOR=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/imx35_updater_defconfig b/arch/arm/configs/imx35_updater_defconfig
index 83ecdac1de88..6d1fed3c8944 100644
--- a/arch/arm/configs/imx35_updater_defconfig
+++ b/arch/arm/configs/imx35_updater_defconfig
@@ -1,6 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.31
+# Sun Jun 13 10:46:18 2010
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -39,10 +40,7 @@ CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_AUDIT is not set
#
# RCU Subsystem
@@ -102,7 +100,6 @@ CONFIG_TRACEPOINTS=y
CONFIG_MARKERS=y
CONFIG_OPROFILE=y
CONFIG_HAVE_OPROFILE=y
-# CONFIG_KPROBES is not set
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
@@ -115,12 +112,7 @@ CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
CONFIG_BASE_SMALL=0
-CONFIG_MODULES=y
-# CONFIG_MODULE_FORCE_LOAD is not set
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_MODULES is not set
CONFIG_BLOCK=y
CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
@@ -155,6 +147,7 @@ CONFIG_FREEZER=y
# CONFIG_ARCH_FOOTBRIDGE is not set
CONFIG_ARCH_MXC=y
# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_MXS is not set
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
# CONFIG_ARCH_IOP13XX is not set
@@ -197,7 +190,7 @@ CONFIG_UTMI_MXC=y
# CONFIG_ARCH_MX25 is not set
CONFIG_ARCH_MX35=y
# CONFIG_ARCH_MX37 is not set
-# CONFIG_ARCH_MX51 is not set
+# CONFIG_ARCH_MX5 is not set
CONFIG_MXC_SDMA_API=y
CONFIG_SDMA_IRAM=y
CONFIG_ARCH_MXC_HAS_NFC_V2=y
@@ -341,105 +334,7 @@ CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
# CONFIG_APM_EMULATION is not set
CONFIG_ARCH_SUSPEND_POSSIBLE=y
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=y
-CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_XFRM_MODE_BEET=y
-# CONFIG_INET_LRO is not set
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_TCP_MD5SIG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_IP_DCCP is not set
-# CONFIG_IP_SCTP is not set
-# CONFIG_TIPC is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_NET_DSA is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_PHONET is not set
-# CONFIG_IEEE802154 is not set
-# CONFIG_NET_SCHED is not set
-# CONFIG_DCB is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NET_DROP_MONITOR is not set
-# CONFIG_HAMRADIO is not set
-CONFIG_CAN=y
-CONFIG_CAN_RAW=y
-CONFIG_CAN_BCM=y
-
-#
-# CAN Device Drivers
-#
-CONFIG_CAN_VCAN=y
-# CONFIG_CAN_DEV is not set
-# CONFIG_CAN_DEBUG_DEVICES is not set
-CONFIG_CAN_FLEXCAN=m
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_AF_RXRPC is not set
-CONFIG_WIRELESS=y
-# CONFIG_CFG80211 is not set
-CONFIG_WIRELESS_OLD_REGULATORY=y
-CONFIG_WIRELESS_EXT=y
-CONFIG_WIRELESS_EXT_SYSFS=y
-# CONFIG_LIB80211 is not set
-
-#
-# CFG80211 needs to be enabled for MAC80211
-#
-CONFIG_MAC80211_DEFAULT_PS_VALUE=0
-# CONFIG_WIMAX is not set
-# CONFIG_RFKILL is not set
-# CONFIG_NET_9P is not set
+# CONFIG_NET is not set
#
# Device Drivers
@@ -455,13 +350,10 @@ CONFIG_FW_LOADER=y
CONFIG_FIRMWARE_IN_KERNEL=y
CONFIG_EXTRA_FIRMWARE=""
# CONFIG_SYS_HYPERVISOR is not set
-CONFIG_CONNECTOR=y
-CONFIG_PROC_EVENTS=y
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
# CONFIG_MTD_CONCAT is not set
CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
CONFIG_MTD_CMDLINE_PARTS=y
# CONFIG_MTD_AFS_PARTS is not set
@@ -540,13 +432,11 @@ CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
-# CONFIG_MTD_NAND_IMX_NFC is not set
CONFIG_MTD_NAND_MXC_V2=y
# CONFIG_MTD_NAND_MXC_SWECC is not set
# CONFIG_MTD_NAND_MXC_FORCE_CE is not set
# CONFIG_MXC_NAND_LOW_LEVEL_ERASE is not set
# CONFIG_MTD_NAND_PLATFORM is not set
-# CONFIG_MTD_ALAUDA is not set
# CONFIG_MTD_ONENAND is not set
#
@@ -557,17 +447,23 @@ CONFIG_MTD_NAND_MXC_V2=y
#
# UBI - Unsorted block images
#
-# CONFIG_MTD_UBI is not set
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+CONFIG_MTD_UBI_BLOCK=y
# CONFIG_PARPORT is not set
CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_UB is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_CDROM_PKTCDVD is not set
-# CONFIG_ATA_OVER_ETH is not set
# CONFIG_MG_DISK is not set
CONFIG_MISC_DEVICES=y
# CONFIG_ICS932S401 is not set
@@ -610,121 +506,28 @@ CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
# CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
#
# SCSI Transports
#
# CONFIG_SCSI_SPI_ATTRS is not set
# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
# CONFIG_SCSI_SAS_LIBSAS is not set
# CONFIG_SCSI_SRP_ATTRS is not set
CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
# CONFIG_LIBFC is not set
# CONFIG_LIBFCOE is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_DH is not set
# CONFIG_SCSI_OSD_INITIATOR is not set
-CONFIG_ATA=m
+CONFIG_ATA=y
# CONFIG_ATA_NONSTANDARD is not set
# CONFIG_SATA_PMP is not set
CONFIG_ATA_SFF=y
# CONFIG_SATA_MV is not set
# CONFIG_PATA_PLATFORM is not set
-CONFIG_PATA_FSL=m
+CONFIG_PATA_FSL=y
# CONFIG_MD is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_VETH is not set
-CONFIG_PHYLIB=y
-
-#
-# MII PHY device drivers
-#
-# CONFIG_MARVELL_PHY is not set
-# CONFIG_DAVICOM_PHY is not set
-# CONFIG_QSEMI_PHY is not set
-# CONFIG_LXT_PHY is not set
-# CONFIG_CICADA_PHY is not set
-# CONFIG_VITESSE_PHY is not set
-# CONFIG_SMSC_PHY is not set
-# CONFIG_BROADCOM_PHY is not set
-# CONFIG_ICPLUS_PHY is not set
-# CONFIG_REALTEK_PHY is not set
-# CONFIG_NATIONAL_PHY is not set
-# CONFIG_STE10XP is not set
-# CONFIG_LSI_ET1011C_PHY is not set
-# CONFIG_FIXED_PHY is not set
-# CONFIG_MDIO_BITBANG is not set
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_AX88796 is not set
-# CONFIG_SMC91X is not set
-# CONFIG_DM9000 is not set
-# CONFIG_ENC28J60 is not set
-# CONFIG_ETHOC is not set
-# CONFIG_SMC911X is not set
-CONFIG_SMSC911X=y
-# CONFIG_DNET is not set
-# CONFIG_IBM_NEW_EMAC_ZMII is not set
-# CONFIG_IBM_NEW_EMAC_RGMII is not set
-# CONFIG_IBM_NEW_EMAC_TAH is not set
-# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
-# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
-# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
-# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
-# CONFIG_B44 is not set
-# CONFIG_CS89x0 is not set
-# CONFIG_KS8842 is not set
-# CONFIG_KS8851 is not set
-# CONFIG_FEC is not set
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-
-#
-# Wireless LAN
-#
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-
-#
-# Enable WiMAX (Networking options) to see the WiMAX drivers
-#
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-CONFIG_USB_USBNET=m
-# CONFIG_USB_NET_AX8817X is not set
-CONFIG_USB_NET_CDCETHER=m
-# CONFIG_USB_NET_CDC_EEM is not set
-# CONFIG_USB_NET_DM9601 is not set
-# CONFIG_USB_NET_SMSC95XX is not set
-# CONFIG_USB_NET_GL620A is not set
-# CONFIG_USB_NET_NET1080 is not set
-# CONFIG_USB_NET_PLUSB is not set
-# CONFIG_USB_NET_MCS7830 is not set
-# CONFIG_USB_NET_RNDIS_HOST is not set
-# CONFIG_USB_NET_CDC_SUBSET is not set
-# CONFIG_USB_NET_ZAURUS is not set
-# CONFIG_USB_NET_INT51X1 is not set
-# CONFIG_WAN is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NETCONSOLE is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_ISDN is not set
#
# Input device support
@@ -798,7 +601,7 @@ CONFIG_HW_CONSOLE=y
# CONFIG_VT_HW_CONSOLE_BINDING is not set
CONFIG_DEVKMEM=y
# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_FM_SI4702=m
+CONFIG_FM_SI4702=y
CONFIG_MXC_IIM=y
#
@@ -849,13 +652,11 @@ CONFIG_I2C_MXC=y
#
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_TAOS_EVM is not set
-# CONFIG_I2C_TINY_USB is not set
#
# Other I2C/SMBus bus drivers
#
# CONFIG_I2C_PCA_PLATFORM is not set
-# CONFIG_I2C_STUB is not set
#
# Miscellaneous I2C Chip support
@@ -925,11 +726,6 @@ CONFIG_WATCHDOG_NOWAYOUT=y
#
# CONFIG_SOFT_WATCHDOG is not set
CONFIG_MXC_WATCHDOG=y
-
-#
-# USB-based Watchdog Cards
-#
-# CONFIG_USBPCWATCHDOG is not set
CONFIG_SSB_POSSIBLE=y
#
@@ -964,13 +760,11 @@ CONFIG_VIDEO_DEV=y
CONFIG_VIDEO_V4L2_COMMON=y
CONFIG_VIDEO_ALLOW_V4L1=y
CONFIG_VIDEO_V4L1_COMPAT=y
-# CONFIG_DVB_CORE is not set
CONFIG_VIDEO_MEDIA=y
#
# Multimedia drivers
#
-# CONFIG_MEDIA_ATTACH is not set
CONFIG_MEDIA_TUNER=y
CONFIG_MEDIA_TUNER_CUSTOMISE=y
# CONFIG_MEDIA_TUNER_SIMPLE is not set
@@ -1068,89 +862,26 @@ CONFIG_VIDEO_CAPTURE_DRIVERS=y
# CONFIG_VIDEO_UPD64031A is not set
# CONFIG_VIDEO_UPD64083 is not set
# CONFIG_VIDEO_VIVI is not set
-CONFIG_VIDEO_MXC_CAMERA=m
+CONFIG_VIDEO_MXC_CAMERA=y
#
# MXC Camera/V4L2 PRP Features support
#
-CONFIG_VIDEO_MXC_IPU_CAMERA=y
# CONFIG_VIDEO_MXC_CSI_CAMERA is not set
# CONFIG_MXC_CAMERA_MC521DA is not set
# CONFIG_MXC_EMMA_CAMERA_MICRON111 is not set
# CONFIG_MXC_CAMERA_OV2640_EMMA is not set
# CONFIG_MXC_CAMERA_MICRON111 is not set
-CONFIG_MXC_CAMERA_OV2640=m
-# CONFIG_MXC_CAMERA_OV3640 is not set
-CONFIG_MXC_TVIN_ADV7180=m
-CONFIG_MXC_IPU_PRP_VF_SDC=m
-CONFIG_MXC_IPU_PRP_ENC=m
-CONFIG_MXC_IPU_CSI_ENC=m
+# CONFIG_MXC_CAMERA_OV2640 is not set
+CONFIG_MXC_CAMERA_OV3640=y
+# CONFIG_MXC_TVIN_ADV7180 is not set
CONFIG_VIDEO_MXC_OUTPUT=y
-CONFIG_VIDEO_MXC_IPU_OUTPUT=y
-# CONFIG_VIDEO_MXC_IPUV1_WVGA_OUTPUT is not set
# CONFIG_VIDEO_MXC_OPL is not set
# CONFIG_VIDEO_CPIA is not set
-# CONFIG_VIDEO_CPIA2 is not set
# CONFIG_VIDEO_SAA5246A is not set
# CONFIG_VIDEO_SAA5249 is not set
# CONFIG_SOC_CAMERA is not set
-CONFIG_V4L_USB_DRIVERS=y
-# CONFIG_USB_VIDEO_CLASS is not set
-CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
-CONFIG_USB_GSPCA=m
-# CONFIG_USB_M5602 is not set
-# CONFIG_USB_STV06XX is not set
-# CONFIG_USB_GSPCA_CONEX is not set
-# CONFIG_USB_GSPCA_ETOMS is not set
-# CONFIG_USB_GSPCA_FINEPIX is not set
-# CONFIG_USB_GSPCA_MARS is not set
-# CONFIG_USB_GSPCA_MR97310A is not set
-# CONFIG_USB_GSPCA_OV519 is not set
-# CONFIG_USB_GSPCA_OV534 is not set
-# CONFIG_USB_GSPCA_PAC207 is not set
-# CONFIG_USB_GSPCA_PAC7311 is not set
-# CONFIG_USB_GSPCA_SN9C20X is not set
-# CONFIG_USB_GSPCA_SONIXB is not set
-# CONFIG_USB_GSPCA_SONIXJ is not set
-# CONFIG_USB_GSPCA_SPCA500 is not set
-# CONFIG_USB_GSPCA_SPCA501 is not set
-# CONFIG_USB_GSPCA_SPCA505 is not set
-# CONFIG_USB_GSPCA_SPCA506 is not set
-# CONFIG_USB_GSPCA_SPCA508 is not set
-# CONFIG_USB_GSPCA_SPCA561 is not set
-# CONFIG_USB_GSPCA_SQ905 is not set
-# CONFIG_USB_GSPCA_SQ905C is not set
-# CONFIG_USB_GSPCA_STK014 is not set
-# CONFIG_USB_GSPCA_SUNPLUS is not set
-# CONFIG_USB_GSPCA_T613 is not set
-# CONFIG_USB_GSPCA_TV8532 is not set
-# CONFIG_USB_GSPCA_VC032X is not set
-# CONFIG_USB_GSPCA_ZC3XX is not set
-# CONFIG_VIDEO_PVRUSB2 is not set
-# CONFIG_VIDEO_HDPVR is not set
-# CONFIG_VIDEO_EM28XX is not set
-# CONFIG_VIDEO_CX231XX is not set
-# CONFIG_VIDEO_USBVISION is not set
-# CONFIG_USB_VICAM is not set
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_KONICAWC is not set
-# CONFIG_USB_QUICKCAM_MESSENGER is not set
-# CONFIG_USB_ET61X251 is not set
-# CONFIG_VIDEO_OVCAMCHIP is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_SE401 is not set
-# CONFIG_USB_SN9C102 is not set
-# CONFIG_USB_STV680 is not set
-# CONFIG_USB_ZC0301 is not set
-# CONFIG_USB_PWC is not set
-CONFIG_USB_PWC_INPUT_EVDEV=y
-# CONFIG_USB_ZR364XX is not set
-# CONFIG_USB_STKWEBCAM is not set
-# CONFIG_USB_S2255 is not set
CONFIG_RADIO_ADAPTERS=y
-# CONFIG_USB_DSBR is not set
-# CONFIG_USB_SI470X is not set
-# CONFIG_USB_MR800 is not set
# CONFIG_RADIO_TEA5764 is not set
# CONFIG_DAB is not set
@@ -1163,9 +894,9 @@ CONFIG_FB=y
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB_DDC is not set
# CONFIG_FB_BOOT_VESA_SUPPORT is not set
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_FB_CFB_COPYAREA=y
-CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
# CONFIG_FB_SYS_FILLRECT is not set
# CONFIG_FB_SYS_COPYAREA is not set
@@ -1181,14 +912,6 @@ CONFIG_FB_MODE_HELPERS=y
#
# Frame buffer hardware drivers
#
-CONFIG_FB_MXC=y
-CONFIG_FB_MXC_SYNC_PANEL=y
-# CONFIG_FB_MXC_EPSON_VGA_SYNC_PANEL is not set
-CONFIG_FB_MXC_CLAA_WVGA_SYNC_PANEL=y
-# CONFIG_FB_MXC_CH7026 is not set
-# CONFIG_FB_MXC_TVOUT_CH7024 is not set
-# CONFIG_FB_MXC_ASYNC_PANEL is not set
-# CONFIG_FB_UVESA is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FB_METRONOME is not set
@@ -1199,7 +922,6 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_BACKLIGHT_GENERIC=y
CONFIG_BACKLIGHT_MXC=y
-CONFIG_BACKLIGHT_MXC_IPU=y
CONFIG_BACKLIGHT_MXC_MC13892=y
#
@@ -1230,211 +952,28 @@ CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_LOGO_LINUX_CLUT224=y
-CONFIG_SOUND=y
-CONFIG_SOUND_OSS_CORE=y
-CONFIG_SND=y
-CONFIG_SND_TIMER=y
-CONFIG_SND_PCM=y
-CONFIG_SND_JACK=y
-# CONFIG_SND_SEQUENCER is not set
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_PCM_OSS_PLUGINS=y
-# CONFIG_SND_HRTIMER is not set
-# CONFIG_SND_DYNAMIC_MINORS is not set
-CONFIG_SND_SUPPORT_OLD_API=y
-CONFIG_SND_VERBOSE_PROCFS=y
-# CONFIG_SND_VERBOSE_PRINTK is not set
-# CONFIG_SND_DEBUG is not set
-# CONFIG_SND_RAWMIDI_SEQ is not set
-# CONFIG_SND_OPL3_LIB_SEQ is not set
-# CONFIG_SND_OPL4_LIB_SEQ is not set
-# CONFIG_SND_SBAWE_SEQ is not set
-# CONFIG_SND_EMU10K1_SEQ is not set
-CONFIG_SND_DRIVERS=y
-# CONFIG_SND_DUMMY is not set
-# CONFIG_SND_MTPAV is not set
-# CONFIG_SND_SERIAL_U16550 is not set
-# CONFIG_SND_MPU401 is not set
-CONFIG_SND_ARM=y
-CONFIG_SND_MXC_SPDIF=m
-CONFIG_SND_SPI=y
-CONFIG_SND_USB=y
-# CONFIG_SND_USB_AUDIO is not set
-# CONFIG_SND_USB_CAIAQ is not set
-CONFIG_SND_SOC=y
-CONFIG_SND_MXC_SOC=y
-CONFIG_SND_MXC_SOC_SSI=y
-CONFIG_SND_MXC_SOC_ESAI=y
-CONFIG_SND_MXC_SOC_IRAM=y
-CONFIG_SND_SOC_IMX_3STACK_SGTL5000=y
-CONFIG_SND_SOC_IMX_3STACK_AK4647=y
-CONFIG_SND_SOC_IMX_3STACK_WM8580=y
-# CONFIG_SND_SOC_IMX_3STACK_AK5702 is not set
-CONFIG_SND_SOC_IMX_3STACK_BLUETOOTH=y
-CONFIG_SND_SOC_I2C_AND_SPI=y
-# CONFIG_SND_SOC_ALL_CODECS is not set
-CONFIG_SND_SOC_WM8580=y
-CONFIG_SND_SOC_SGTL5000=y
-CONFIG_SND_SOC_AK4647=y
-CONFIG_SND_SOC_BLUETOOTH=y
-# CONFIG_SOUND_PRIME is not set
+# CONFIG_SOUND is not set
CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
# CONFIG_HIDRAW is not set
-
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=m
# CONFIG_HID_PID is not set
-# CONFIG_USB_HIDDEV is not set
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
#
# Special HID drivers
#
-CONFIG_HID_A4TECH=m
-CONFIG_HID_APPLE=m
-CONFIG_HID_BELKIN=m
-CONFIG_HID_CHERRY=m
-CONFIG_HID_CHICONY=m
-CONFIG_HID_CYPRESS=m
-# CONFIG_HID_DRAGONRISE is not set
-CONFIG_HID_EZKEY=m
-# CONFIG_HID_KYE is not set
-CONFIG_HID_GYRATION=m
-# CONFIG_HID_KENSINGTON is not set
-CONFIG_HID_LOGITECH=m
-# CONFIG_LOGITECH_FF is not set
-# CONFIG_LOGIRUMBLEPAD2_FF is not set
-CONFIG_HID_MICROSOFT=m
-CONFIG_HID_MONTEREY=m
-# CONFIG_HID_NTRIG is not set
-CONFIG_HID_PANTHERLORD=m
-# CONFIG_PANTHERLORD_FF is not set
-CONFIG_HID_PETALYNX=m
-CONFIG_HID_SAMSUNG=m
-CONFIG_HID_SONY=m
-CONFIG_HID_SUNPLUS=m
-# CONFIG_HID_GREENASIA is not set
-# CONFIG_HID_SMARTJOYPLUS is not set
-# CONFIG_HID_TOPSEED is not set
-# CONFIG_HID_THRUSTMASTER is not set
-# CONFIG_HID_ZEROPLUS is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
# CONFIG_USB_ARCH_HAS_OHCI is not set
CONFIG_USB_ARCH_HAS_EHCI=y
-CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_DEVICE_CLASS=y
-# CONFIG_USB_DYNAMIC_MINORS is not set
-CONFIG_USB_SUSPEND=y
-# CONFIG_USB_OTG is not set
+# CONFIG_USB is not set
# CONFIG_USB_OTG_WHITELIST is not set
# CONFIG_USB_OTG_BLACKLIST_HUB is not set
-CONFIG_USB_MON=y
-# CONFIG_USB_WUSB is not set
-# CONFIG_USB_WUSB_CBAF is not set
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_C67X00_HCD is not set
-CONFIG_USB_EHCI_HCD=m
-CONFIG_USB_EHCI_ARC=y
-CONFIG_USB_EHCI_ARC_H2=y
-# CONFIG_USB_EHCI_ARC_OTG is not set
-# CONFIG_USB_STATIC_IRAM is not set
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_OXU210HP_HCD is not set
-# CONFIG_USB_ISP116X_HCD is not set
-# CONFIG_USB_ISP1760_HCD is not set
-# CONFIG_USB_SL811_HCD is not set
-# CONFIG_USB_R8A66597_HCD is not set
-# CONFIG_USB_HWA_HCD is not set
# CONFIG_USB_GADGET_MUSB_HDRC is not set
#
-# USB Device Class drivers
-#
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-# CONFIG_USB_WDM is not set
-# CONFIG_USB_TMC is not set
-
-#
# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
#
-
-#
-# also be needed; see USB_STORAGE Help for more info
-#
-CONFIG_USB_STORAGE=y
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_USBAT is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_SDDR55 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_STORAGE_ALAUDA is not set
-# CONFIG_USB_STORAGE_ONETOUCH is not set
-# CONFIG_USB_STORAGE_KARMA is not set
-# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
-# CONFIG_USB_LIBUSUAL is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_MICROTEK is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_SERIAL is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_EMI62 is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_ADUTUX is not set
-# CONFIG_USB_SEVSEG is not set
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_LEGOTOWER is not set
-# CONFIG_USB_LCD is not set
-# CONFIG_USB_BERRY_CHARGE is not set
-# CONFIG_USB_LED is not set
-# CONFIG_USB_CYPRESS_CY7C63 is not set
-# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_IDMOUSE is not set
-# CONFIG_USB_FTDI_ELAN is not set
-# CONFIG_USB_APPLEDISPLAY is not set
-# CONFIG_USB_SISUSBVGA is not set
-# CONFIG_USB_LD is not set
-# CONFIG_USB_TRANCEVIBRATOR is not set
-# CONFIG_USB_IOWARRIOR is not set
-# CONFIG_USB_TEST is not set
-# CONFIG_USB_ISIGHTFW is not set
-# CONFIG_USB_VST is not set
CONFIG_USB_GADGET=y
# CONFIG_USB_GADGET_DEBUG_FILES is not set
# CONFIG_USB_GADGET_DEBUG_FS is not set
@@ -1465,7 +1004,7 @@ CONFIG_USB_GADGET_DUALSPEED=y
# CONFIG_USB_AUDIO is not set
# CONFIG_USB_ETH is not set
# CONFIG_USB_GADGETFS is not set
-CONFIG_USB_FILE_STORAGE=m
+CONFIG_USB_FILE_STORAGE=y
CONFIG_FSL_UTP=y
# CONFIG_USB_FILE_STORAGE_TEST is not set
# CONFIG_USB_G_SERIAL is not set
@@ -1479,7 +1018,6 @@ CONFIG_FSL_UTP=y
CONFIG_USB_OTG_UTILS=y
# CONFIG_USB_GPIO_VBUS is not set
# CONFIG_NOP_USB_XCEIV is not set
-# CONFIG_MXC_OTG is not set
CONFIG_MMC=y
# CONFIG_MMC_DEBUG is not set
CONFIG_MMC_UNSAFE_RESUME=y
@@ -1491,7 +1029,7 @@ CONFIG_MMC_BLOCK=y
CONFIG_MMC_BLOCK_BOUNCE=y
# CONFIG_SDIO_UART is not set
# CONFIG_MMC_TEST is not set
-CONFIG_SDIO_UNIFI_FS=m
+CONFIG_SDIO_UNIFI_FS=y
#
# MMC/SD/SDIO Host Controller Drivers
@@ -1499,7 +1037,7 @@ CONFIG_SDIO_UNIFI_FS=m
# CONFIG_MMC_SDHCI is not set
# CONFIG_MMC_MXC is not set
# CONFIG_MMC_SPI is not set
-CONFIG_MMC_IMX_ESDHCI=m
+CONFIG_MMC_IMX_ESDHCI=y
# CONFIG_MMC_IMX_ESDHCI_PIO_MODE is not set
# CONFIG_MEMSTICK is not set
# CONFIG_ACCESSIBILITY is not set
@@ -1588,9 +1126,7 @@ CONFIG_REGULATOR_MC9S08DZ60=y
#
# MXC support drivers
#
-CONFIG_MXC_IPU=y
-CONFIG_MXC_IPU_V1=y
-CONFIG_MXC_IPU_PF=y
+# CONFIG_MXC_IPU is not set
#
# MXC SSI support
@@ -1657,17 +1193,17 @@ CONFIG_MXC_ASRC=y
#
# MXC Bluetooth support
#
-CONFIG_MXC_BLUETOOTH=m
+CONFIG_MXC_BLUETOOTH=y
#
# Broadcom GPS ioctrl support
#
-CONFIG_GPS_IOCTRL=m
+CONFIG_GPS_IOCTRL=y
#
# MXC Media Local Bus Driver
#
-CONFIG_MXC_MLB=m
+CONFIG_MXC_MLB=y
#
# i.MX ADC support
@@ -1677,15 +1213,25 @@ CONFIG_MXC_MLB=m
#
# File systems
#
-# CONFIG_EXT2_FS is not set
-# CONFIG_EXT3_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FS_POSIX_ACL=y
# CONFIG_XFS_FS is not set
# CONFIG_GFS2_FS is not set
-# CONFIG_OCFS2_FS is not set
# CONFIG_BTRFS_FS is not set
CONFIG_FILE_LOCKING=y
CONFIG_FSNOTIFY=y
@@ -1694,7 +1240,7 @@ CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
-CONFIG_AUTOFS4_FS=m
+CONFIG_AUTOFS4_FS=y
# CONFIG_FUSE_FS is not set
#
@@ -1740,6 +1286,12 @@ CONFIG_MISC_FILESYSTEMS=y
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_JFFS2_FS is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
# CONFIG_CRAMFS is not set
# CONFIG_SQUASHFS is not set
# CONFIG_VXFS_FS is not set
@@ -1751,7 +1303,6 @@ CONFIG_MISC_FILESYSTEMS=y
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
# CONFIG_NILFS2_FS is not set
-# CONFIG_NETWORK_FILESYSTEMS is not set
#
# Partition Types
@@ -1783,7 +1334,7 @@ CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
-CONFIG_NLS_ASCII=m
+CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
@@ -1797,8 +1348,7 @@ CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
-CONFIG_NLS_UTF8=m
-# CONFIG_DLM is not set
+CONFIG_NLS_UTF8=y
#
# Kernel hacking
@@ -1847,13 +1397,14 @@ CONFIG_CRYPTO=y
# Crypto core or helper
#
# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
# CONFIG_CRYPTO_MANAGER is not set
# CONFIG_CRYPTO_MANAGER2 is not set
# CONFIG_CRYPTO_GF128MUL is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_CRYPTD is not set
# CONFIG_CRYPTO_AUTHENC is not set
-# CONFIG_CRYPTO_TEST is not set
# CONFIG_CRYPTO_CRYPTODEV is not set
#
@@ -1919,9 +1470,9 @@ CONFIG_CRYPTO=y
#
# Compression
#
-# CONFIG_CRYPTO_DEFLATE is not set
+CONFIG_CRYPTO_DEFLATE=y
# CONFIG_CRYPTO_ZLIB is not set
-# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_LZO=y
#
# Random Number Generation
@@ -1935,17 +1486,19 @@ CONFIG_BINARY_PRINTF=y
#
CONFIG_BITREVERSE=y
CONFIG_GENERIC_FIND_LAST_BIT=y
-CONFIG_CRC_CCITT=m
-# CONFIG_CRC16 is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
# CONFIG_CRC_T10DIF is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
CONFIG_DECOMPRESS_GZIP=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
-CONFIG_NLATTR=y
diff --git a/arch/arm/configs/imx5_defconfig b/arch/arm/configs/imx5_defconfig
index 9934ad7403f6..47cf51acaa53 100644
--- a/arch/arm/configs/imx5_defconfig
+++ b/arch/arm/configs/imx5_defconfig
@@ -178,7 +178,7 @@ CONFIG_ARCH_MXC=y
# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_OMAP is not set
CONFIG_IRAM_ALLOC=y
-CONFIG_DMA_ZONE_SIZE=64
+CONFIG_DMA_ZONE_SIZE=96
CONFIG_UTMI_MXC=y
#
@@ -197,11 +197,15 @@ CONFIG_FORCE_MAX_ZONEORDER=13
CONFIG_ARCH_MXC_HAS_NFC_V3=y
CONFIG_ARCH_MX51=y
CONFIG_ARCH_MX53=y
+CONFIG_ARCH_MX50=y
CONFIG_MX5_OPTIONS=y
CONFIG_MX5_MULTI_ARCH=y
CONFIG_MACH_MX51_3DS=y
CONFIG_MACH_MX51_BABBAGE=y
CONFIG_MACH_MX53_EVK=y
+CONFIG_MACH_MX50_ARM2=y
+CONFIG_MACH_MX50_RDP=y
+CONFIG_ARCH_MXC_IOMUX_V3=y
#
# MX5x Options:
@@ -418,7 +422,17 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_HAMRADIO is not set
-# CONFIG_CAN is not set
+CONFIG_CAN=y
+CONFIG_CAN_RAW=y
+CONFIG_CAN_BCM=y
+
+#
+# CAN Device Drivers
+#
+CONFIG_CAN_VCAN=y
+# CONFIG_CAN_DEV is not set
+CONFIG_CAN_DEBUG_DEVICES=y
+CONFIG_CAN_FLEXCAN=y
# CONFIG_IRDA is not set
CONFIG_BT=y
CONFIG_BT_L2CAP=y
@@ -475,7 +489,7 @@ CONFIG_CONNECTOR=y
CONFIG_PROC_EVENTS=y
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_TESTS is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
@@ -622,6 +636,7 @@ CONFIG_SCSI_LOWLEVEL=y
CONFIG_ATA=m
# CONFIG_ATA_NONSTANDARD is not set
# CONFIG_SATA_PMP is not set
+CONFIG_SATA_AHCI_PLATFORM=m
CONFIG_ATA_SFF=y
# CONFIG_SATA_MV is not set
# CONFIG_PATA_PLATFORM is not set
@@ -676,6 +691,7 @@ CONFIG_SMSC911X=y
# CONFIG_KS8842 is not set
# CONFIG_KS8851 is not set
CONFIG_FEC=y
+# CONFIG_FEC_1588 is not set
# CONFIG_FEC2 is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
@@ -811,6 +827,7 @@ CONFIG_DEVKMEM=y
# CONFIG_SERIAL_NONSTANDARD is not set
CONFIG_FM_SI4702=m
CONFIG_MXC_IIM=y
+CONFIG_MXS_VIIM=y
CONFIG_IMX_SIM=m
#
@@ -1186,7 +1203,7 @@ CONFIG_VIDEO_MXC_IPU_CAMERA=y
# CONFIG_MXC_CAMERA_MICRON111 is not set
# CONFIG_MXC_CAMERA_OV2640 is not set
CONFIG_MXC_CAMERA_OV3640=m
-# CONFIG_MXC_TVIN_ADV7180 is not set
+CONFIG_MXC_TVIN_ADV7180=m
CONFIG_MXC_IPU_PRP_VF_SDC=m
CONFIG_MXC_IPU_PRP_ENC=m
CONFIG_MXC_IPU_CSI_ENC=m
@@ -1277,6 +1294,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_SYS_IMAGEBLIT is not set
# CONFIG_FB_FOREIGN_ENDIAN is not set
# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
# CONFIG_FB_SVGALIB is not set
# CONFIG_FB_MACMODES is not set
# CONFIG_FB_BACKLIGHT is not set
@@ -1290,10 +1308,14 @@ CONFIG_FB_MXC=y
CONFIG_FB_MXC_SYNC_PANEL=y
CONFIG_FB_MXC_EPSON_VGA_SYNC_PANEL=y
CONFIG_FB_MXC_TVOUT_TVE=y
+CONFIG_FB_MXC_LDB=y
# CONFIG_FB_MXC_CLAA_WVGA_SYNC_PANEL is not set
+CONFIG_FB_MXC_SII9022=y
CONFIG_FB_MXC_CH7026=y
# CONFIG_FB_MXC_TVOUT_CH7024 is not set
# CONFIG_FB_MXC_ASYNC_PANEL is not set
+CONFIG_FB_MXC_EINK_PANEL=y
+# CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE is not set
# CONFIG_FB_UVESA is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
@@ -1372,14 +1394,17 @@ CONFIG_SND_USB=y
CONFIG_SND_SOC=y
CONFIG_SND_MXC_SOC=y
CONFIG_SND_MXC_SOC_SSI=y
+CONFIG_SND_MXC_SOC_ESAI=y
CONFIG_SND_MXC_SOC_IRAM=y
CONFIG_SND_SOC_IMX_3STACK_SGTL5000=y
# CONFIG_SND_SOC_IMX_3STACK_AK4647 is not set
# CONFIG_SND_SOC_IMX_3STACK_WM8580 is not set
# CONFIG_SND_SOC_IMX_3STACK_AK5702 is not set
# CONFIG_SND_SOC_IMX_3STACK_BLUETOOTH is not set
+CONFIG_SND_SOC_IMX_3STACK_CS42888=y
CONFIG_SND_SOC_I2C_AND_SPI=y
# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_CS42888=y
CONFIG_SND_SOC_SGTL5000=y
# CONFIG_SOUND_PRIME is not set
CONFIG_HID_SUPPORT=y
@@ -1684,7 +1709,21 @@ CONFIG_RTC_INTF_DEV_UIE_EMUL=y
# CONFIG_RTC_DRV_MXC_V2 is not set
# CONFIG_RTC_DRV_IMXDI is not set
CONFIG_RTC_MC13892=y
-# CONFIG_DMADEVICES is not set
+CONFIG_DMADEVICES=y
+
+#
+# DMA Devices
+#
+CONFIG_MXC_PXP=y
+CONFIG_MXC_PXP_CLIENT_DEVICE=y
+CONFIG_DMA_ENGINE=y
+
+#
+# DMA Clients
+#
+# CONFIG_NET_DMA is not set
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_DMATEST is not set
# CONFIG_AUXDISPLAY is not set
CONFIG_REGULATOR=y
# CONFIG_REGULATOR_DEBUG is not set
@@ -1695,6 +1734,7 @@ CONFIG_REGULATOR=y
# CONFIG_REGULATOR_MAX1586 is not set
# CONFIG_REGULATOR_LP3971 is not set
CONFIG_REGULATOR_MC13892=y
+CONFIG_REGULATOR_MAX17135=y
CONFIG_UIO=y
# CONFIG_UIO_PDRV is not set
CONFIG_UIO_PDRV_GENIRQ=m
@@ -1787,6 +1827,7 @@ CONFIG_GPS_IOCTRL=m
#
# MXC Media Local Bus Driver
#
+CONFIG_MXC_MLB=m
#
# i.MX ADC support
@@ -1794,6 +1835,11 @@ CONFIG_GPS_IOCTRL=m
# CONFIG_IMX_ADC is not set
#
+# MXC GPU support
+#
+CONFIG_MXC_AMD_GPU=m
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -2019,8 +2065,8 @@ CONFIG_CRYPTO=y
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_CRYPTD is not set
# CONFIG_CRYPTO_AUTHENC is not set
-# CONFIG_CRYPTO_TEST is not set
-# CONFIG_CRYPTO_CRYPTODEV is not set
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_CRYPTODEV=y
#
# Authenticated Encryption with Associated Data
@@ -2032,10 +2078,10 @@ CONFIG_CRYPTO=y
#
# Block modes
#
-# CONFIG_CRYPTO_CBC is not set
+CONFIG_CRYPTO_CBC=y
# CONFIG_CRYPTO_CTR is not set
# CONFIG_CRYPTO_CTS is not set
-# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_ECB=y
# CONFIG_CRYPTO_LRW is not set
# CONFIG_CRYPTO_PCBC is not set
# CONFIG_CRYPTO_XTS is not set
@@ -2066,7 +2112,7 @@ CONFIG_CRYPTO=y
#
# Ciphers
#
-# CONFIG_CRYPTO_AES is not set
+CONFIG_CRYPTO_AES=y
# CONFIG_CRYPTO_ANUBIS is not set
# CONFIG_CRYPTO_ARC4 is not set
# CONFIG_CRYPTO_BLOWFISH is not set
diff --git a/arch/arm/include/asm/mach/flash.h b/arch/arm/include/asm/mach/flash.h
index 4ca69fe2c850..8b57c2ed6d7e 100644
--- a/arch/arm/include/asm/mach/flash.h
+++ b/arch/arm/include/asm/mach/flash.h
@@ -34,6 +34,7 @@ struct flash_platform_data {
void (*mmcontrol)(struct mtd_info *mtd, int sync_read);
struct mtd_partition *parts;
unsigned int nr_parts;
+ char *type;
};
#endif
diff --git a/arch/arm/mach-mx23/Kconfig b/arch/arm/mach-mx23/Kconfig
index 0a122b009687..28009b0d62cb 100644
--- a/arch/arm/mach-mx23/Kconfig
+++ b/arch/arm/mach-mx23/Kconfig
@@ -7,3 +7,19 @@ config MACH_MX23EVK
select USB_ARCH_HAS_EHCI
endchoice
+
+
+config MXS_UNIQUE_ID
+ bool "Support for UniqueID on boot media"
+ default y
+
+config MXS_UNIQUE_ID_OTP
+ bool "UniqueID on OTP"
+ depends on MXS_UNIQUE_ID
+ default y
+
+config VECTORS_PHY_ADDR
+ int "vectors address"
+ default 0
+ help
+ This config set vectors table is located which physical address
diff --git a/arch/arm/mach-mx23/Makefile b/arch/arm/mach-mx23/Makefile
index 622981c9572d..a5e278190326 100644
--- a/arch/arm/mach-mx23/Makefile
+++ b/arch/arm/mach-mx23/Makefile
@@ -7,6 +7,7 @@ obj-y += pinctrl.o clock.o device.o serial.o power.o pm.o sleep.o bus_freq.o
obj-$(CONFIG_MACH_MX23EVK) += mx23evk.o mx23evk_pins.o
obj-$(CONFIG_GENERIC_GPIO) += gpio.o
obj-$(CONFIG_MXS_RAM_FREQ_SCALING) +=emi.o
+obj-$(CONFIG_MXS_UNIQUE_ID_OTP) += otp.o
# USB support
ifneq ($(strip $(CONFIG_USB_GADGET_ARC) $(CONFIG_USB_EHCI_ARC_OTG)),)
diff --git a/arch/arm/mach-mx23/bus_freq.c b/arch/arm/mach-mx23/bus_freq.c
index b4efabdfefcc..9133e6b1080a 100644
--- a/arch/arm/mach-mx23/bus_freq.c
+++ b/arch/arm/mach-mx23/bus_freq.c
@@ -46,36 +46,32 @@
#define CLKCTRL_BASE_ADDR IO_ADDRESS(CLKCTRL_PHYS_ADDR)
#define DIGCTRL_BASE_ADDR IO_ADDRESS(DIGCTL_PHYS_ADDR)
-#define BP_CLKCTRL_HBUS_ASM_ENABLE 20
-#define CLKCTRL_PLL_PWD_BIT 17
-#define CLKCTRL_PLL_BYPASS 0x1ff
#define BF(value, field) (((value) << BP_##field) & BM_##field)
struct profile profiles[] = {
{ 454736, 151580, 130910, 0, 1550000,
- 1450000, 355000, 3300000, 1750000, 0 },
- { 392727, 130910, 130910, 0, 1475000,
- 1375000, 225000, 3300000, 1750000, 0 },
- { 360000, 120000, 120000, 0, 1375000,
- 1275000, 200000, 3300000, 1750000, 0 },
+ 1450000, 355000, 3300000, 1750000, 24000, 0 },
+ { 392727, 130910, 130910, 0, 1450000,
+ 1375000, 225000, 3300000, 1750000, 24000, 0x1CF3 },
+ { 360000, 120000, 130910, 0, 1375000,
+ 1275000, 200000, 3300000, 1750000, 24000, 0x1CF3 },
{ 261818, 130910, 130910, 0, 1275000,
- 1175000, 173000, 3300000, 1750000, 0 },
+ 1175000, 173000, 3300000, 1750000, 24000, 0x1CF3 },
#ifdef CONFIG_MXS_RAM_MDDR
{ 64000, 64000, 48000, 3, 1050000,
- 975000, 150000, 3300000, 1750000, 0 },
+ 975000, 150000, 3300000, 1750000, 24000, 0x1CF3 },
{ 24000, 24000, 24000, 3, 1050000,
- 975000, 150000, 3075000, 1725000, 1 },
+ 975000, 150000, 3075000, 1725000, 6000, 0x1C93 },
#else
{ 64000, 64000, 96000, 3, 1050000,
- 975000, 150000, 3300000, 1750000, 0 },
- { 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0 },
+ 975000, 150000, 3300000, 1750000, 24000, 0x1CF3 },
+ { 24000, 24000, 96000, 3, 1050000,
+ 975000, 150000, 3300000, 1725000, 6000, 0x1C93 },
#endif
};
static struct clk *usb_clk;
static struct clk *lcdif_clk;
-u32 clkseq_setting;
int low_freq_used(void)
{
@@ -84,60 +80,14 @@ int low_freq_used(void)
return 1;
else
return 0;
- }
-
-void hbus_auto_slow_mode_enable(void)
-{
- __raw_writel(BP_CLKCTRL_HBUS_ASM_ENABLE,
- CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_SET);
-}
-EXPORT_SYMBOL(hbus_auto_slow_mode_enable);
-
-void hbus_auto_slow_mode_disable(void)
-{
- __raw_writel(BP_CLKCTRL_HBUS_ASM_ENABLE,
- CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR);
}
-EXPORT_SYMBOL(hbus_auto_slow_mode_disable);
-int cpu_clk_set_pll_on(struct clk *clk, unsigned int freq)
+int is_hclk_autoslow_ok(void)
{
- struct cpufreq_freqs freqs;
-
- freqs.old = clk_get_rate(clk);
- freqs.cpu = 0;
- freqs.new = freq;
-
- if (freqs.old == 24000 && freqs.new > 24000) {
- /* turn pll on */
- __raw_writel(CLKCTRL_PLL_PWD_BIT, CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_PLLCTRL0_SET);
- udelay(10);
- } else if (freqs.old > 24000 && freqs.new == 24000)
- clkseq_setting = __raw_readl(CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_CLKSEQ);
- return 0;
-}
-
-int cpu_clk_set_pll_off(struct clk *clk, unsigned int freq)
-{
- struct cpufreq_freqs freqs;
-
- freqs.old = clk_get_rate(clk);
- freqs.cpu = 0;
- freqs.new = freq;
-
- if (freqs.old > 24000 && freqs.new == 24000) {
- /* turn pll off */
- __raw_writel(CLKCTRL_PLL_PWD_BIT, CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_PLLCTRL0_CLR);
- __raw_writel(CLKCTRL_PLL_BYPASS, CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_CLKSEQ);
- } else if (freqs.old == 24000 && freqs.new > 24000)
- __raw_writel(clkseq_setting, CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_CLKSEQ);
-
- return 0;
+ if (clk_get_usecount(usb_clk) == 0)
+ return 1;
+ else
+ return 0;
}
int timing_ctrl_rams(int ss)
diff --git a/arch/arm/mach-mx23/clock.c b/arch/arm/mach-mx23/clock.c
index 957a70213399..9e18dbc74337 100644
--- a/arch/arm/mach-mx23/clock.c
+++ b/arch/arm/mach-mx23/clock.c
@@ -18,10 +18,12 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/err.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/iram_alloc.h>
#include <linux/platform_device.h>
#include <mach/clock.h>
@@ -29,17 +31,130 @@
#include "regs-clkctrl.h"
#include "regs-digctl.h"
+#include <mach/regs-rtc.h>
#include <mach/mx23.h>
#define CLKCTRL_BASE_ADDR IO_ADDRESS(CLKCTRL_PHYS_ADDR)
#define DIGCTRL_BASE_ADDR IO_ADDRESS(DIGCTL_PHYS_ADDR)
+#define RTC_BASE_ADDR IO_ADDRESS(RTC_PHYS_ADDR)
+
+/* these are the maximum clock speeds that have been
+ * validated to run at the minumum VddD target voltage level for cpu operation
+ * (presently 1.05V target, .975V Brownout). Higher clock speeds for GPMI and
+ * SSP have not been validated.
+ */
+#define PLL_ENABLED_MAX_CLK_SSP 96000000
+#define PLL_ENABLED_MAX_CLK_GPMI 96000000
+
/* external clock input */
-static struct clk xtal_clk[];
-static unsigned long xtal_clk_rate[3] = { 24000000, 24000000, 32000 };
+static struct clk pll_clk;
+static struct clk ref_xtal_clk;
+
+#ifdef DEBUG
+static void print_ref_counts(void);
+#endif
static unsigned long enet_mii_phy_rate;
+static inline int clk_is_busy(struct clk *clk)
+{
+ if ((clk->parent == &ref_xtal_clk) && (clk->xtal_busy_bits))
+ return __raw_readl(clk->busy_reg) & (1 << clk->xtal_busy_bits);
+ else if (clk->busy_bits && clk->busy_reg)
+ return __raw_readl(clk->busy_reg) & (1 << clk->busy_bits);
+ else {
+ printk(KERN_ERR "WARNING: clock has no assigned busy \
+ register or bits\n");
+ udelay(10);
+ return 0;
+ }
+}
+
+static inline int clk_busy_wait(struct clk *clk)
+{
+ int i;
+
+ for (i = 10000000; i; i--)
+ if (!clk_is_busy(clk))
+ break;
+ if (!i)
+ return -ETIMEDOUT;
+ else
+ return 0;
+}
+
+static bool mx23_enable_h_autoslow(bool enable)
+{
+ bool currently_enabled;
+
+ if (__raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_HBUS) &
+ BM_CLKCTRL_HBUS_AUTO_SLOW_MODE)
+ currently_enabled = true;
+ else
+ currently_enabled = false;
+
+ if (enable)
+ __raw_writel(BM_CLKCTRL_HBUS_AUTO_SLOW_MODE,
+ CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_SET);
+ else
+ __raw_writel(BM_CLKCTRL_HBUS_AUTO_SLOW_MODE,
+ CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR);
+ return currently_enabled;
+}
+
+
+static void mx23_set_hbus_autoslow_flags(u16 mask)
+{
+ u32 reg;
+
+ reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
+ reg &= 0xFFFF;
+ reg |= mask << 16;
+ __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
+}
+
+static void local_clk_disable(struct clk *clk)
+{
+ if (clk == NULL || IS_ERR(clk) || !clk->ref)
+ return;
+
+ if ((--clk->ref) & CLK_EN_MASK)
+ return;
+
+ if (clk->disable)
+ clk->disable(clk);
+ local_clk_disable(clk->secondary);
+ local_clk_disable(clk->parent);
+}
+
+static int local_clk_enable(struct clk *clk)
+{
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
+ if ((clk->ref++) & CLK_EN_MASK)
+ return 0;
+ if (clk->parent)
+ local_clk_enable(clk->parent);
+ if (clk->secondary)
+ local_clk_enable(clk->secondary);
+ if (clk->enable)
+ clk->enable(clk);
+ return 0;
+}
+
+
+static bool mx23_is_clk_enabled(struct clk *clk)
+{
+ if (clk->enable_reg)
+ return (__raw_readl(clk->enable_reg) &
+ clk->enable_bits) ? 0 : 1;
+ else
+ return (clk->ref & CLK_EN_MASK) ? 1 : 0;
+}
+
+
static int mx23_raw_enable(struct clk *clk)
{
unsigned int reg;
@@ -48,6 +163,9 @@ static int mx23_raw_enable(struct clk *clk)
reg &= ~clk->enable_bits;
__raw_writel(reg, clk->enable_reg);
}
+ if (clk->busy_reg)
+ clk_busy_wait(clk);
+
return 0;
}
@@ -61,29 +179,14 @@ static void mx23_raw_disable(struct clk *clk)
}
}
-static unsigned long xtal_get_rate(struct clk *clk)
+static unsigned long ref_xtal_get_rate(struct clk *clk)
{
- int id = clk - xtal_clk;
- return xtal_clk_rate[id];
+ return 24000000;
}
-static struct clk xtal_clk[] = {
- {
- .flags = RATE_FIXED,
- .get_rate = xtal_get_rate,
- },
- {
- .flags = RATE_FIXED,
- .get_rate = xtal_get_rate,
- },
- {
- .flags = RATE_FIXED,
- .get_rate = xtal_get_rate,
- },
-};
-
static struct clk ref_xtal_clk = {
- .parent = &xtal_clk[0],
+ .flags = RATE_FIXED,
+ .get_rate = ref_xtal_get_rate,
};
static unsigned long pll_get_rate(struct clk *clk);
@@ -107,20 +210,23 @@ static unsigned long pll_get_rate(struct clk *clk)
static int pll_enable(struct clk *clk)
{
- int timeout = 100;
- unsigned long reg;
+ u32 reg;
+
+ reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_PLLCTRL0);
+
+ if ((reg & BM_CLKCTRL_PLLCTRL0_POWER) &&
+ (reg & BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS))
+ return 0;
__raw_writel(BM_CLKCTRL_PLLCTRL0_POWER |
BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS,
CLKCTRL_BASE_ADDR + HW_CLKCTRL_PLLCTRL0_SET);
- do {
- udelay(10);
- reg = __raw_readl(CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_PLLCTRL1);
- timeout--;
- } while ((timeout > 0) && !(reg & BM_CLKCTRL_PLLCTRL1_LOCK));
- if (timeout <= 0)
- return -EFAULT;
+ /* only a 10us delay is need. PLLCTRL1 LOCK bitfied is only a timer
+ * and is incorrect (excessive). Per definition of the PLLCTRL0
+ * POWER field, waiting at least 10us.
+ */
+ udelay(10);
+
return 0;
}
@@ -171,6 +277,8 @@ static unsigned long ref_cpu_get_rate(struct clk *clk)
static struct clk ref_cpu_clk = {
.parent = &pll_clk,
+ .enable = mx23_raw_enable,
+ .disable = mx23_raw_disable,
.get_rate = ref_cpu_get_rate,
.round_rate = ref_clk_round_rate,
.set_rate = ref_clk_set_rate,
@@ -178,6 +286,8 @@ static struct clk ref_cpu_clk = {
.enable_bits = BM_CLKCTRL_FRAC_CLKGATECPU,
.scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC,
.scale_bits = BP_CLKCTRL_FRAC_CPUFRAC,
+ .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU,
+ .busy_bits = 28,
};
static unsigned long ref_emi_get_rate(struct clk *clk)
@@ -191,6 +301,8 @@ static unsigned long ref_emi_get_rate(struct clk *clk)
static struct clk ref_emi_clk = {
.parent = &pll_clk,
+ .enable = mx23_raw_enable,
+ .disable = mx23_raw_disable,
.get_rate = ref_emi_get_rate,
.set_rate = ref_clk_set_rate,
.round_rate = ref_clk_round_rate,
@@ -202,10 +314,12 @@ static struct clk ref_emi_clk = {
static unsigned long ref_io_get_rate(struct clk *clk);
static struct clk ref_io_clk = {
- .parent = &pll_clk,
- .get_rate = ref_io_get_rate,
- .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC,
- .enable_bits = BM_CLKCTRL_FRAC_CLKGATEIO,
+ .parent = &pll_clk,
+ .enable = mx23_raw_enable,
+ .disable = mx23_raw_disable,
+ .get_rate = ref_io_get_rate,
+ .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC,
+ .enable_bits = BM_CLKCTRL_FRAC_CLKGATEIO,
};
static unsigned long ref_io_get_rate(struct clk *clk)
@@ -229,6 +343,8 @@ static unsigned long ref_pix_get_rate(struct clk *clk)
static struct clk ref_pix_clk = {
.parent = &pll_clk,
+ .enable = mx23_raw_enable,
+ .disable = mx23_raw_disable,
.get_rate = ref_pix_get_rate,
.enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC,
.enable_bits = BM_CLKCTRL_FRAC_CLKGATEPIX,
@@ -237,63 +353,20 @@ static struct clk ref_pix_clk = {
static struct clk cpu_clk, h_clk;
static int clkseq_set_parent(struct clk *clk, struct clk *parent)
{
- int ret = -EINVAL;
- int shift = 8;
+ int shift;
+ if (clk->parent == parent)
+ return 0; /* clock parent already at target. nothing to do */
/* bypass? */
if (parent == &ref_xtal_clk)
shift = 4;
+ else
+ shift = 8;
- if (clk->bypass_reg) {
- u32 hbus_val, cpu_val;
-
- if (clk == &cpu_clk && shift == 4) {
- hbus_val = __raw_readl(CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_HBUS);
- cpu_val = __raw_readl(CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_CPU);
-
- hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN |
- BM_CLKCTRL_HBUS_DIV);
- hbus_val |= 1;
-
- cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU;
- cpu_val |= 1;
-
- __raw_writel(1 << clk->bypass_bits,
- clk->bypass_reg + shift);
-
- __raw_writel(hbus_val,
- CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
- __raw_writel(cpu_val,
- CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU);
- /* h_clk.rate = 0; */
- } else if (clk == &cpu_clk && shift == 8) {
- hbus_val = __raw_readl(CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_HBUS);
- cpu_val = __raw_readl(CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_CPU);
- hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN |
- BM_CLKCTRL_HBUS_DIV);
- hbus_val |= 2;
- cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU;
- cpu_val |= 2;
-
- __raw_writel(hbus_val,
- CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
- __raw_writel(cpu_val,
- CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU);
- /* h_clk.rate = 0; */
+ if (clk->bypass_reg)
+ __raw_writel(1 << clk->bypass_bits, clk->bypass_reg + shift);
- __raw_writel(1 << clk->bypass_bits,
- clk->bypass_reg + shift);
- } else
- __raw_writel(1 << clk->bypass_bits,
- clk->bypass_reg + shift);
- ret = 0;
- }
-
- return ret;
+ return 0;
}
static unsigned long lcdif_get_rate(struct clk *clk)
@@ -336,6 +409,8 @@ static int lcdif_set_rate(struct clk *clk, unsigned long rate)
ns_cycle *= 2; /* Fix calculate double frequency */
+
+
for (div = 1; div < 256; ++div) {
u32 fracdiv;
u32 ps_result;
@@ -394,16 +469,9 @@ static int lcdif_set_rate(struct clk *clk, unsigned long rate)
__raw_writel(reg_val, clk->scale_reg);
/* Wait for divider update */
- if (clk->busy_reg) {
- int i;
- for (i = 10000; i; i--)
- if (!clk_is_busy(clk))
- break;
- if (!i) {
- ret = -ETIMEDOUT;
- goto out;
- }
- }
+ ret = clk_busy_wait(clk);
+ if (ret)
+ goto out;
/* Switch to ref_pix source */
reg_val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ);
@@ -414,6 +482,14 @@ out:
return ret;
}
+/*
+ * We set lcdif_clk's parent as &pll_clk deliberately, although
+ * in IC spec lcdif_clk(CLK_PIX) is derived from ref_pix which in turn
+ * is derived from PLL. By doing so, users just need to set/get clock rate
+ * for lcdif_clk, without need to take care of ref_pix, because the clock
+ * driver will automatically calculate the fracdivider for HW_CLKCTRL_FRAC
+ * and the divider for HW_CLKCTRL_PIX conjointly.
+ */
static struct clk lcdif_clk = {
.parent = &pll_clk,
.enable = mx23_raw_enable,
@@ -464,20 +540,77 @@ static unsigned long cpu_round_rate(struct clk *clk, unsigned long rate)
static int cpu_set_rate(struct clk *clk, unsigned long rate)
{
- unsigned long root_rate =
- clk->parent->parent->get_rate(clk->parent->parent);
- int i;
+ unsigned long root_rate = pll_clk.get_rate(&pll_clk);
+ int ret = -EINVAL;
u32 clkctrl_cpu = 1;
u32 c = clkctrl_cpu;
u32 clkctrl_frac = 1;
u32 val;
- u32 reg_val;
+ u32 reg_val, hclk_reg;
+ bool h_autoslow;
- if (rate < 24000000)
+ /* make sure the cpu div_xtal is 1 */
+ reg_val = __raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_CPU);
+ reg_val &= ~(BM_CLKCTRL_CPU_DIV_XTAL);
+ reg_val |= (1 << BP_CLKCTRL_CPU_DIV_XTAL);
+ __raw_writel(reg_val, CLKCTRL_BASE_ADDR+HW_CLKCTRL_CPU);
+
+ if (rate < ref_xtal_get_rate(&ref_xtal_clk))
return -EINVAL;
- else if (rate == 24000000) {
+
+ if (rate == clk_get_rate(clk))
+ return 0;
+ /* temporaily disable h autoslow to avoid
+ * hclk getting too slow while temporarily
+ * changing clocks
+ */
+ h_autoslow = mx23_enable_h_autoslow(false);
+
+ if (rate == ref_xtal_get_rate(&ref_xtal_clk)) {
+
/* switch to the 24M source */
clk_set_parent(clk, &ref_xtal_clk);
+
+ /* to avoid bus starvation issues, we'll go ahead
+ * and change hbus clock divider to 1 now. Cpufreq
+ * or other clock management can lower it later if
+ * desired for power savings or other reasons, but
+ * there should be no need to with hbus autoslow
+ * functionality enabled.
+ */
+
+ ret = clk_busy_wait(&cpu_clk);
+ if (ret) {
+ printk(KERN_ERR "* couldn't set\
+ up CPU divisor\n");
+ return ret;
+ }
+
+ ret = clk_busy_wait(&h_clk);
+ if (ret) {
+ printk(KERN_ERR "* H_CLK busy timeout\n");
+ return ret;
+ }
+
+ hclk_reg = __raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_HBUS);
+ hclk_reg &= ~(BM_CLKCTRL_HBUS_DIV);
+ hclk_reg |= (1 << BP_CLKCTRL_HBUS_DIV);
+
+ __raw_writel(hclk_reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_SET);
+
+ ret = clk_busy_wait(&cpu_clk);
+ if (ret) {
+ printk(KERN_ERR "** couldn't set\
+ up CPU divisor\n");
+ return ret;
+ }
+
+ ret = clk_busy_wait(&h_clk);
+ if (ret) {
+ printk(KERN_ERR "** CLK busy timeout\n");
+ return ret;
+ }
+
} else {
for ( ; c < 0x40; c++) {
u32 f = ((root_rate/1000)*18/c + (rate/1000)/2) /
@@ -502,33 +635,116 @@ static int cpu_set_rate(struct clk *clk, unsigned long rate)
if ((abs(d) > 100) || (clkctrl_frac < 18) ||
(clkctrl_frac > 35))
return -EINVAL;
- }
+ }
- /* Set Frac div */
+ /* prepare Frac div */
val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC);
- val &= ~(BM_CLKCTRL_FRAC_CPUFRAC << BP_CLKCTRL_FRAC_CPUFRAC);
- val |= clkctrl_frac;
- __raw_writel(val, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC);
- /* Do not gate */
- __raw_writel(BM_CLKCTRL_FRAC_CLKGATECPU, CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_FRAC_CLR);
+ val &= ~(BM_CLKCTRL_FRAC_CPUFRAC);
+ val |= (clkctrl_frac << BP_CLKCTRL_FRAC_CPUFRAC);
- /* write clkctrl_cpu */
+ /* prepare clkctrl_cpu div*/
reg_val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU);
reg_val &= ~0x3F;
reg_val |= clkctrl_cpu;
+ /* set safe hbus clock divider. A divider of 3 ensure that
+ * the Vddd voltage required for the cpuclk is sufficiently
+ * high for the hbus clock and under 24MHz cpuclk conditions,
+ * a divider of at least 3 ensures hbusclk doesn't remain
+ * uneccesarily low which hurts performance
+ */
+ hclk_reg = __raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_HBUS);
+ hclk_reg &= ~(BM_CLKCTRL_HBUS_DIV);
+ hclk_reg |= (3 << BP_CLKCTRL_HBUS_DIV);
+
+ /* if the pll was OFF, we need to turn it ON.
+ * Even if it was ON, we want to temporarily
+ * increment it by 1 to avoid turning off
+ * in the upcoming parent clock change to xtal. This
+ * avoids waiting an extra 10us for every cpu clock
+ * change between ref_cpu sourced frequencies.
+ */
+ pll_enable(&pll_clk);
+ pll_clk.ref++;
+
+ /* switch to XTAL CLK source temparily while
+ * we manipulate ref_cpu frequency */
+ clk_set_parent(clk, &ref_xtal_clk);
+
+ ret = clk_busy_wait(&h_clk);
+
+ if (ret) {
+ printk(KERN_ERR "-* HCLK busy wait timeout\n");
+ return ret;
+ }
+
+ ret = clk_busy_wait(clk);
+
+ if (ret) {
+ printk(KERN_ERR "-* couldn't set\
+ up CPU divisor\n");
+ return ret;
+ }
+
+ __raw_writel(val, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC);
+
+ /* clear the gate */
+ __raw_writel(BM_CLKCTRL_FRAC_CLKGATECPU, CLKCTRL_BASE_ADDR +
+ HW_CLKCTRL_FRAC_CLR);
+
+ /* set the ref_cpu integer divider */
__raw_writel(reg_val, CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU);
- for (i = 10000; i; i--)
- if (!clk_is_busy(clk))
- break;
- if (!i) {
- printk(KERN_ERR "couldn't set up CPU divisor\n");
- return -ETIMEDOUT;
+ /* wait for the ref_cpu path to become stable before
+ * switching over to it
+ */
+
+ ret = clk_busy_wait(&ref_cpu_clk);
+
+ if (ret) {
+ printk(KERN_ERR "-** couldn't set\
+ up CPU divisor\n");
+ return ret;
}
+
+ /* change hclk divider to safe value for any ref_cpu
+ * value.
+ */
+ __raw_writel(hclk_reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
+
+ ret = clk_busy_wait(&h_clk);
+
+ if (ret) {
+ printk(KERN_ERR "-** HCLK busy wait timeout\n");
+ return ret;
+ }
+
+ clk_set_parent(clk, &ref_cpu_clk);
+
+ /* decrement the pll_clk ref count because
+ * we temporarily enabled/incremented the count
+ * above.
+ */
+ pll_clk.ref--;
+
+ ret = clk_busy_wait(&cpu_clk);
+
+ if (ret) {
+ printk(KERN_ERR "-*** Couldn't set\
+ up CPU divisor\n");
+ return ret;
+ }
+
+ ret = clk_busy_wait(&h_clk);
+
+ if (ret) {
+ printk(KERN_ERR "-*** HCLK busy wait timeout\n");
+ return ret;
+ }
+
}
- return 0;
+ mx23_enable_h_autoslow(h_autoslow);
+ return ret;
}
static struct clk cpu_clk = {
@@ -543,6 +759,7 @@ static struct clk cpu_clk = {
.bypass_bits = 7,
.busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU,
.busy_bits = 28,
+ .xtal_busy_bits = 29,
};
static unsigned long uart_get_rate(struct clk *clk)
@@ -598,25 +815,99 @@ static unsigned long x_get_rate(struct clk *clk)
return clk->parent->get_rate(clk->parent) / reg;
}
+static unsigned long x_round_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned int root_rate, frac_rate;
+ unsigned int div;
+ root_rate = clk->parent->get_rate(clk->parent);
+ frac_rate = root_rate % rate;
+ div = root_rate / rate;
+ /* while the reference manual specifies that divider
+ * values up to 1023 are aloud, other critial SoC compents
+ * require higher x clock values at all times. Through
+ * limited testing, the lradc functionality to measure
+ * the battery voltage and copy this value to the
+ * power supply requires at least a 64kHz xclk.
+ * so the divider will be limited to 375.
+ */
+ if ((div == 0) || (div > 375))
+ return root_rate;
+ if (frac_rate == 0)
+ return rate;
+ else
+ return root_rate / (div + 1);
+}
+
+static int x_set_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned long root_rate;
+ unsigned long round_rate;
+ unsigned int reg, div;
+ root_rate = clk->parent->get_rate(clk->parent);
+
+ if ((!clk->round_rate) || !(clk->scale_reg))
+ return -EINVAL;
+
+ round_rate = clk->round_rate(clk, rate);
+ div = root_rate / round_rate;
+
+ if (root_rate % round_rate)
+ return -EINVAL;
+
+ reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS);
+ reg &= ~(BM_CLKCTRL_XBUS_DIV_FRAC_EN | BM_CLKCTRL_XBUS_DIV);
+ reg |= BF_CLKCTRL_XBUS_DIV(div);
+ __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS);
+
+ return clk_busy_wait(clk);
+
+}
+
static struct clk x_clk = {
.parent = &ref_xtal_clk,
.get_rate = x_get_rate,
+ .set_rate = x_set_rate,
+ .round_rate = x_round_rate,
+ .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS,
+ .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS,
+ .busy_bits = 31,
};
+
+
static struct clk ana_clk = {
.parent = &ref_xtal_clk,
};
-static unsigned long rtc_get_rate(struct clk *clk)
+
+
+static unsigned long xtal_clock32k_get_rate(struct clk *clk)
{
- if (clk->parent == &xtal_clk[2])
- return clk->parent->get_rate(clk->parent);
- return clk->parent->get_rate(clk->parent) / 768;
+ if (__raw_readl(RTC_BASE_ADDR + HW_RTC_PERSISTENT0) &
+ BM_RTC_PERSISTENT0_XTAL32_FREQ)
+ return 32000;
+ else
+ return 32768;
}
-static struct clk rtc_clk = {
- .parent = &ref_xtal_clk,
- .get_rate = rtc_get_rate,
+static struct clk xtal_clock32k_clk = {
+ .get_rate = xtal_clock32k_get_rate,
+};
+
+static unsigned long rtc32k_get_rate(struct clk *clk)
+{
+ if (clk->parent == &ref_xtal_clk)
+ /* mx23 reference manual had error.
+ * fixed divider is 750 not 768
+ */
+ return clk->parent->get_rate(clk->parent) / 750;
+ else
+ return xtal_clock32k_get_rate(clk);
+}
+
+static struct clk rtc32k_clk = {
+ .parent = &xtal_clock32k_clk,
+ .get_rate = rtc32k_get_rate,
};
static unsigned long h_get_rate(struct clk *clk)
@@ -656,23 +947,14 @@ static int h_set_rate(struct clk *clk, unsigned long rate)
if (root_rate % round_rate)
return -EINVAL;
- if ((root_rate < rate) && (root_rate == 64000000))
- div = 3;
-
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
reg &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN | BM_CLKCTRL_HBUS_DIV);
reg |= BF_CLKCTRL_HBUS_DIV(div);
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
- if (clk->busy_reg) {
- int i;
- for (i = 10000; i; i--)
- if (!clk_is_busy(clk))
- break;
- if (!i) {
- printk(KERN_ERR "couldn't set up AHB divisor\n");
- return -ETIMEDOUT;
- }
+ if (clk_busy_wait(clk)) {
+ printk(KERN_ERR "couldn't set up AHB divisor\n");
+ return -EINVAL;
}
return 0;
@@ -720,29 +1002,39 @@ static unsigned long emi_round_rate(struct clk *clk, unsigned long rate)
return root_rate / div;
}
+/* when changing the emi clock, dram access must be
+ * disabled. Special handling is needed to perform
+ * the emi clock change without touching sdram.
+ */
static int emi_set_rate(struct clk *clk, unsigned long rate)
{
int ret = 0;
- if (rate < 24000)
+ struct mxs_emi_scaling_data sc_data;
+
+ unsigned long clkctrl_emi;
+ unsigned long clkctrl_frac;
+ int div = 1;
+ unsigned long root_rate, cur_emi_div, cur_emi_frac;
+ struct clk *target_parent_p = &ref_xtal_clk;
+
+ if (rate < ref_xtal_get_rate(&ref_xtal_clk))
return -EINVAL;
- else {
- int i;
- struct mxs_emi_scaling_data sc_data;
- int (*scale)(struct mxs_emi_scaling_data *) =
- (void *)(MX23_OCRAM_BASE + 0x1000);
- void *saved_ocram;
- unsigned long clkctrl_emi;
- unsigned long clkctrl_frac;
- int div = 1;
- unsigned long root_rate =
- clk->parent->parent->get_rate(clk->parent->parent);
- /*
- * We've been setting div to HW_CLKCTRL_CPU_RD() & 0x3f so far.
- * TODO: verify 1 is still valid.
- */
- if (!mxs_ram_funcs_sz)
- goto out;
+
+ if (!mxs_ram_funcs_sz)
+ goto out;
+
+ sc_data.cur_freq = (clk->get_rate(clk)) / 1000 / 1000;
+ sc_data.new_freq = rate / 1000 / 1000;
+
+ if (sc_data.cur_freq == sc_data.new_freq)
+ goto out;
+
+ if (rate != ref_xtal_get_rate(&ref_xtal_clk)) {
+ target_parent_p = &ref_emi_clk;
+ pll_enable(&pll_clk);
+
+ root_rate = pll_clk.get_rate(&pll_clk);
for (clkctrl_emi = div; clkctrl_emi < 0x3f;
clkctrl_emi += div) {
@@ -764,37 +1056,62 @@ static int emi_set_rate(struct clk *clk, unsigned long rate)
pr_debug("%s: clkctrl_emi %ld, clkctrl_frac %ld\n",
__func__, clkctrl_emi, clkctrl_frac);
- saved_ocram = kmalloc(mxs_ram_funcs_sz, GFP_KERNEL);
- if (!saved_ocram)
- return -ENOMEM;
- memcpy(saved_ocram, scale, mxs_ram_funcs_sz);
- memcpy(scale, mxs_ram_freq_scale, mxs_ram_funcs_sz);
-
sc_data.emi_div = clkctrl_emi;
sc_data.frac_div = clkctrl_frac;
- sc_data.cur_freq = (clk->get_rate(clk)) / 1000 / 1000;
- sc_data.new_freq = rate / 1000 / 1000;
+ }
+
+
+ cur_emi_div = ((__raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_EMI) &
+ BM_CLKCTRL_EMI_DIV_EMI) >> BP_CLKCTRL_EMI_DIV_EMI);
+ cur_emi_frac = ((__raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_FRAC) &
+ BM_CLKCTRL_EMI_DIV_EMI) >> BP_CLKCTRL_FRAC_EMIFRAC);
+
+ if ((cur_emi_div == sc_data.emi_div) &&
+ (cur_emi_frac == sc_data.frac_div))
+ goto out;
+ {
+ unsigned long iram_phy;
+ bool h_autoslow;
+ int (*scale)(struct mxs_emi_scaling_data *) =
+ iram_alloc(mxs_ram_funcs_sz, &iram_phy);
+
+ if (NULL == scale) {
+ pr_err("%s Not enough iram\n", __func__);
+ return -ENOMEM;
+ }
+
+ /* temporaily disable h autoslow to maximize
+ * performance/minimize time spent with no
+ * sdram access
+ */
+ h_autoslow = mx23_enable_h_autoslow(false);
+
+ memcpy(scale, mxs_ram_freq_scale, mxs_ram_funcs_sz);
local_irq_disable();
local_fiq_disable();
scale(&sc_data);
+ iram_free(iram_phy, mxs_ram_funcs_sz);
+
local_fiq_enable();
local_irq_enable();
- for (i = 10000; i; i--)
- if (!clk_is_busy(clk))
- break;
- memcpy(scale, saved_ocram, mxs_ram_funcs_sz);
- kfree(saved_ocram);
-
- if (!i) {
- printk(KERN_ERR "couldn't set up EMI divisor\n");
- ret = -ETIMEDOUT;
- goto out;
- }
+ /* temporaily disable h autoslow to avoid
+ * hclk getting too slow while temporarily
+ * changing clocks
+ */
+ mx23_enable_h_autoslow(h_autoslow);
}
+
+ /* this code is for keeping track of ref counts.
+ * and disabling previous parent if necessary
+ * actual clkseq changes have already
+ * been made.
+ */
+ clk_set_parent(clk, target_parent_p);
+
out:
return ret;
}
@@ -812,8 +1129,9 @@ static struct clk emi_clk = {
.scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC,
.busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_EMI,
.busy_bits = 28,
+ .xtal_busy_bits = 29,
.bypass_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ,
- .bypass_bits = 7,
+ .bypass_bits = 6,
};
static unsigned long ssp_get_rate(struct clk *clk);
@@ -821,37 +1139,40 @@ static unsigned long ssp_get_rate(struct clk *clk);
static int ssp_set_rate(struct clk *clk, unsigned long rate)
{
int ret = -EINVAL;
- int div = (clk_get_rate(clk->parent) + rate - 1) / rate;
- u32 reg_frac;
- const int mask = 0x1FF;
- int try = 10;
- int i = -1;
+ u32 reg, div;
+ bool is_clk_enable;
- if (div == 0 || div > mask)
- goto out;
+ is_clk_enable = mx23_is_clk_enabled(clk);
+ if (!is_clk_enable)
+ local_clk_enable(clk);
- reg_frac = __raw_readl(clk->scale_reg);
- reg_frac &= ~(mask << clk->scale_bits);
+ /* if the desired clock can be sourced from ref_xtal,
+ * use ref_xtal to save power
+ */
+ if ((rate <= ref_xtal_get_rate(&ref_xtal_clk)) &&
+ ((ref_xtal_get_rate(&ref_xtal_clk) % rate) == 0))
+ clk_set_parent(clk, &ref_xtal_clk);
+ else
+ clk_set_parent(clk, &ref_io_clk);
- while (try--) {
- __raw_writel(reg_frac | (div << clk->scale_bits),
- clk->scale_reg);
+ if (rate > PLL_ENABLED_MAX_CLK_SSP)
+ rate = PLL_ENABLED_MAX_CLK_SSP;
- if (clk->busy_reg) {
- for (i = 10000; i; i--)
- if (!clk_is_busy(clk))
- break;
- }
- if (i)
- break;
- }
+ div = (clk_get_rate(clk->parent) + rate - 1) / rate;
- if (!i)
- ret = -ETIMEDOUT;
- else
- ret = 0;
+ if (div == 0 || div > BM_CLKCTRL_SSP_DIV)
+ goto out;
+
+ reg = __raw_readl(clk->scale_reg);
+ reg &= ~(BM_CLKCTRL_SSP_DIV | BM_CLKCTRL_SSP_DIV_FRAC_EN);
+ reg |= div << clk->scale_bits;
+ __raw_writel(reg, clk->scale_reg);
+ ret = clk_busy_wait(clk);
out:
+ if (!is_clk_enable)
+ local_clk_disable(clk);
+
if (ret != 0)
printk(KERN_ERR "%s: error %d\n", __func__, ret);
return ret;
@@ -877,6 +1198,26 @@ static int ssp_set_parent(struct clk *clk, struct clk *parent)
return ret;
}
+/* handle peripheral clocks whose optimal parent dependent on
+ * system parameters such as cpu_clk rate. For now, this optimization
+ * only occurs to the peripheral clock when it's not in use to avoid
+ * handling more complex system clock coordination issues.
+ */
+static int ssp_set_sys_dependent_parent(struct clk *clk)
+{
+ if ((clk->ref & CLK_EN_MASK) == 0) {
+ if (clk_get_rate(&cpu_clk) > ref_xtal_get_rate(&ref_xtal_clk)) {
+ clk_set_parent(clk, &ref_io_clk);
+ clk_set_rate(clk, PLL_ENABLED_MAX_CLK_SSP);
+ } else {
+ clk_set_parent(clk, &ref_xtal_clk);
+ clk_set_rate(clk, ref_xtal_get_rate(&ref_xtal_clk));
+ }
+ }
+
+ return 0;
+}
+
static struct clk ssp_clk = {
.parent = &ref_io_clk,
.get_rate = ssp_get_rate,
@@ -889,9 +1230,10 @@ static struct clk ssp_clk = {
.scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP,
.scale_bits = 0,
.bypass_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ,
- .bypass_bits = 3,
+ .bypass_bits = 5,
.set_rate = ssp_set_rate,
.set_parent = ssp_set_parent,
+ .set_sys_dependent_parent = ssp_set_sys_dependent_parent,
};
static unsigned long ssp_get_rate(struct clk *clk)
@@ -903,6 +1245,123 @@ static unsigned long ssp_get_rate(struct clk *clk)
return clk->parent->get_rate(clk->parent) / reg;
}
+static unsigned long gpmi_get_rate(struct clk *clk)
+{
+ unsigned int reg;
+ reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI) &
+ BM_CLKCTRL_GPMI_DIV;
+
+ return clk->parent->get_rate(clk->parent) / reg;
+}
+
+static int gpmi_set_rate(struct clk *clk, unsigned long rate)
+{
+ int ret = -EINVAL;
+ u32 reg, div;
+
+ /* Make absolutely certain the clock is enabled. */
+ local_clk_enable(clk);
+
+ /* if the desired clock can be sourced from ref_xtal,
+ * use ref_xtal to save power
+ */
+ if ((rate <= ref_xtal_get_rate(&ref_xtal_clk)) &&
+ ((ref_xtal_get_rate(&ref_xtal_clk) % rate) == 0))
+ clk_set_parent(clk, &ref_xtal_clk);
+ else
+ clk_set_parent(clk, &ref_io_clk);
+
+ if (rate > PLL_ENABLED_MAX_CLK_SSP)
+ rate = PLL_ENABLED_MAX_CLK_GPMI;
+
+ div = (clk_get_rate(clk->parent) + rate - 1) / rate;
+
+ if (div == 0 || div > BM_CLKCTRL_GPMI_DIV)
+ goto out;
+
+ reg = __raw_readl(clk->scale_reg);
+ reg &= ~(BM_CLKCTRL_GPMI_DIV | BM_CLKCTRL_GPMI_DIV_FRAC_EN);
+ reg |= div << clk->scale_bits;
+ __raw_writel(reg, clk->scale_reg);
+
+ ret = clk_busy_wait(clk);
+
+out:
+
+ /* Undo the enable above. */
+ local_clk_disable(clk);
+
+ if (ret != 0)
+ printk(KERN_ERR "%s: error %d\n", __func__, ret);
+ return ret;
+}
+
+static int gpmi_set_parent(struct clk *clk, struct clk *parent)
+{
+ int ret = -EINVAL;
+
+ if (clk->bypass_reg) {
+ if (clk->parent == parent)
+ return 0;
+ if (parent == &ref_io_clk)
+ __raw_writel(1 << clk->bypass_bits,
+ clk->bypass_reg + CLR_REGISTER);
+ else
+ __raw_writel(1 << clk->bypass_bits,
+ clk->bypass_reg + SET_REGISTER);
+ clk->parent = parent;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/* handle peripheral clocks whose optimal parent dependent on
+ * system parameters such as cpu_clk rate. For now, this optimization
+ * only occurs to the peripheral clock when it's not in use to avoid
+ * handling more complex system clock coordination issues.
+ */
+static int gpmi_set_sys_dependent_parent(struct clk *clk)
+{
+
+ if ((clk->ref & CLK_EN_MASK) == 0) {
+ if (clk_get_rate(&cpu_clk) > ref_xtal_get_rate(&ref_xtal_clk)) {
+ clk_set_parent(clk, &ref_io_clk);
+ clk_set_rate(clk, PLL_ENABLED_MAX_CLK_GPMI);
+ } else {
+ clk_set_parent(clk, &ref_xtal_clk);
+ clk_set_rate(clk, ref_xtal_get_rate(&ref_xtal_clk));
+ }
+ }
+
+ return 0;
+}
+
+static struct clk gpmi_clk = {
+ .parent = &ref_io_clk,
+ .secondary = 0,
+ .flags = 0,
+ .set_parent = gpmi_set_parent,
+ .set_sys_dependent_parent = gpmi_set_sys_dependent_parent,
+
+ .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI,
+ .enable_bits = BM_CLKCTRL_GPMI_CLKGATE,
+ .enable = mx23_raw_enable,
+ .disable = mx23_raw_disable,
+
+ .scale_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI,
+ .scale_bits = 0,
+ .round_rate = 0,
+ .set_rate = gpmi_set_rate,
+ .get_rate = gpmi_get_rate,
+
+ .bypass_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ,
+ .bypass_bits = 4,
+
+ .busy_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI,
+ .busy_bits = 29,
+};
+
static unsigned long pcmspdif_get_rate(struct clk *clk)
{
return clk->parent->get_rate(clk->parent) / 4;
@@ -935,21 +1394,34 @@ static struct clk audio_clk = {
.enable_bits = BM_CLKCTRL_XTAL_FILT_CLK24M_GATE,
};
+static struct clk vid_clk = {
+ .parent = &ref_xtal_clk,
+ .enable = mx23_raw_enable,
+ .disable = mx23_raw_disable,
+ .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC1,
+ .enable_bits = BM_CLKCTRL_FRAC1_CLKGATEVID,
+};
+
+static struct clk tv108M_ng_clk = {
+ .parent = &vid_clk,
+ .enable = mx23_raw_enable,
+ .disable = mx23_raw_disable,
+ .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_TV,
+ .enable_bits = BM_CLKCTRL_TV_CLK_TV108M_GATE,
+ .flags = RATE_FIXED,
+};
+
+static struct clk tv27M_clk = {
+ .parent = &vid_clk,
+ .enable = mx23_raw_enable,
+ .disable = mx23_raw_disable,
+ .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_TV,
+ .enable_bits = BM_CLKCTRL_TV_CLK_TV_GATE,
+ .flags = RATE_FIXED,
+};
static struct clk_lookup onchip_clocks[] = {
{
- .con_id = "xtal.0",
- .clk = &xtal_clk[0],
- },
- {
- .con_id = "xtal.1",
- .clk = &xtal_clk[1],
- },
- {
- .con_id = "xtal.2",
- .clk = &xtal_clk[2],
- },
- {
.con_id = "pll.0",
.clk = &pll_clk,
},
@@ -978,8 +1450,12 @@ static struct clk_lookup onchip_clocks[] = {
.clk = &lcdif_clk,
},
{
+ .con_id = "xtal_clock32k",
+ .clk = &xtal_clock32k_clk,
+ },
+ {
.con_id = "rtc",
- .clk = &rtc_clk,
+ .clk = &rtc32k_clk,
},
{
.con_id = "cpu",
@@ -1032,9 +1508,53 @@ static struct clk_lookup onchip_clocks[] = {
{
.con_id = "spdif",
.clk = &pcmspdif_clk,
- }
+ },
+ {
+ .con_id = "ref_vid",
+ .clk = &vid_clk,
+ },
+ {
+ .con_id = "tv108M_ng",
+ .clk = &tv108M_ng_clk,
+ },
+ {
+ .con_id = "tv27M",
+ .clk = &tv27M_clk,
+ },
+ {
+ .con_id = "gpmi",
+ .clk = &gpmi_clk,
+ },
};
+/* for debugging */
+#ifdef DEBUG
+static void print_ref_counts(void)
+{
+
+ printk(KERN_INFO "pll_clk ref count: %i\n",
+ pll_clk.ref & CLK_EN_MASK);
+
+ printk(KERN_INFO "ref_cpu_clk ref count: %i\n",
+ ref_cpu_clk.ref & CLK_EN_MASK);
+
+ printk(KERN_INFO "ref_emi_clk ref count: %i\n",
+ ref_emi_clk.ref & CLK_EN_MASK);
+
+ printk(KERN_INFO "lcdif_clk ref count: %i\n",
+ lcdif_clk.ref & CLK_EN_MASK);
+
+ printk(KERN_INFO "ref_io_clk ref count: %i\n",
+ ref_io_clk.ref & CLK_EN_MASK);
+
+ printk(KERN_INFO "ssp_clk ref count: %i\n",
+ ssp_clk.ref & CLK_EN_MASK);
+
+ printk(KERN_INFO "gpmi_clk ref count: %i\n",
+ gpmi_clk.ref & CLK_EN_MASK);
+
+}
+#endif
static void mx23_clock_scan(void)
{
@@ -1046,16 +1566,19 @@ static void mx23_clock_scan(void)
emi_clk.parent = &ref_xtal_clk;
if (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SSP)
ssp_clk.parent = &ref_xtal_clk;
-};
+ if (reg & BM_CLKCTRL_CLKSEQ_BYPASS_GPMI)
+ gpmi_clk.parent = &ref_xtal_clk;
+ reg = __raw_readl(RTC_BASE_ADDR + HW_RTC_PERSISTENT0);
+ if (!(reg & BM_RTC_PERSISTENT0_CLOCKSOURCE))
+ rtc32k_clk.parent = &ref_xtal_clk;
+};
void __init mx23_set_input_clk(unsigned long xtal0,
unsigned long xtal1,
unsigned long xtal2, unsigned long enet)
{
- xtal_clk_rate[0] = xtal0;
- xtal_clk_rate[1] = xtal1;
- xtal_clk_rate[2] = xtal2;
+
}
void __init mx23_clock_init(void)
@@ -1067,4 +1590,7 @@ void __init mx23_clock_init(void)
clk_enable(&cpu_clk);
clk_enable(&emi_clk);
+
+ clk_en_public_h_asm_ctrl(mx23_enable_h_autoslow,
+ mx23_set_hbus_autoslow_flags);
}
diff --git a/arch/arm/mach-mx23/device.c b/arch/arm/mach-mx23/device.c
index 38ad3f77181f..cda2285ec3bc 100644
--- a/arch/arm/mach-mx23/device.c
+++ b/arch/arm/mach-mx23/device.c
@@ -28,6 +28,7 @@
#include <linux/mmc/host.h>
#include <linux/phy.h>
#include <linux/fec.h>
+#include <linux/gpmi-nfc.h>
#include <asm/mach/map.h>
@@ -43,6 +44,7 @@
#include "device.h"
#include "mx23_pins.h"
+#include "mx23evk.h"
#include "mach/mx23.h"
#if defined(CONFIG_SERIAL_MXS_DUART) || \
@@ -510,69 +512,97 @@ static void __init mx23_init_dcp(void)
}
#endif
-#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE)
-#define MMC0_POWER MXS_PIN_TO_GPIO(PINID_PWM3)
-#define MMC0_WP MXS_PIN_TO_GPIO(PINID_PWM4)
+#if defined(CONFIG_MTD_NAND_GPMI_NFC)
-static int mxs_mmc_get_wp_mmc0(void)
+static int gpmi_nfc_platform_init(unsigned int max_chip_count)
{
- return gpio_get_value(MMC0_WP);
+ return 0;
}
-static int mxs_mmc_hw_init_mmc0(void)
+static void gpmi_nfc_platform_exit(unsigned int max_chip_count)
{
- int ret = 0;
-
- /* Configure write protect GPIO pin */
- ret = gpio_request(MMC0_WP, "mmc0_wp");
- if (ret) {
- pr_err("wp\r\n");
- goto out_wp;
- }
- gpio_set_value(MMC0_WP, 0);
- gpio_direction_input(MMC0_WP);
-
- /* Configure POWER pin as gpio to drive power to MMC slot */
- ret = gpio_request(MMC0_POWER, "mmc0_power");
- if (ret) {
- pr_err("power\r\n");
- goto out_power;
- }
- gpio_direction_output(MMC0_POWER, 0);
- mdelay(100);
+}
- return 0;
+static const char *gpmi_nfc_partition_source_types[] = { "cmdlinepart", 0 };
+
+static struct gpmi_nfc_platform_data gpmi_nfc_platform_data = {
+ .nfc_version = 0,
+ .boot_rom_version = 0,
+ .clock_name = "gpmi",
+ .platform_init = gpmi_nfc_platform_init,
+ .platform_exit = gpmi_nfc_platform_exit,
+ .min_prop_delay_in_ns = 5,
+ .max_prop_delay_in_ns = 9,
+ .max_chip_count = 2,
+ .boot_area_size_in_bytes = 20 * SZ_1M,
+ .partition_source_types = gpmi_nfc_partition_source_types,
+ .partitions = 0,
+ .partition_count = 0,
+};
-out_power:
- gpio_free(MMC0_WP);
-out_wp:
- return ret;
-}
+static struct resource gpmi_nfc_resources[] = {
+ {
+ .name = GPMI_NFC_GPMI_REGS_ADDR_RES_NAME,
+ .flags = IORESOURCE_MEM,
+ .start = GPMI_PHYS_ADDR,
+ .end = GPMI_PHYS_ADDR + SZ_8K - 1,
+ },
+ {
+ .name = GPMI_NFC_GPMI_INTERRUPT_RES_NAME,
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_GPMI_ATTENTION,
+ .end = IRQ_GPMI_ATTENTION,
+ },
+ {
+ .name = GPMI_NFC_BCH_REGS_ADDR_RES_NAME,
+ .flags = IORESOURCE_MEM,
+ .start = BCH_PHYS_ADDR,
+ .end = BCH_PHYS_ADDR + SZ_8K - 1,
+ },
+ {
+ .name = GPMI_NFC_BCH_INTERRUPT_RES_NAME,
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_BCH,
+ .end = IRQ_BCH,
+ },
+ {
+ .name = GPMI_NFC_DMA_CHANNELS_RES_NAME,
+ .flags = IORESOURCE_DMA,
+ .start = MXS_DMA_CHANNEL_AHB_APBH_GPMI0,
+ .end = MXS_DMA_CHANNEL_AHB_APBH_GPMI3,
+ },
+ {
+ .name = GPMI_NFC_DMA_INTERRUPT_RES_NAME,
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_GPMI_DMA,
+ .end = IRQ_GPMI_DMA,
+ },
+};
-static void mxs_mmc_hw_release_mmc0(void)
+static void __init mx23_init_gpmi_nfc(void)
{
- gpio_free(MMC0_POWER);
- gpio_free(MMC0_WP);
+ struct platform_device *pdev;
+ pdev = mxs_get_device(GPMI_NFC_DRIVER_NAME, 0);
+ if (pdev == NULL || IS_ERR(pdev))
+ return;
+ pdev->dev.platform_data = &gpmi_nfc_platform_data;
+ pdev->resource = gpmi_nfc_resources;
+ pdev->num_resources = ARRAY_SIZE(gpmi_nfc_resources);
+ mxs_add_device(pdev, 1);
}
-
-static void mxs_mmc_cmd_pullup_mmc0(int enable)
+#else
+static void mx23_init_gpmi_nfc(void)
{
- mxs_set_pullup(PINID_SSP1_CMD, enable, "mmc0_cmd");
}
+#endif
+#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE)
static unsigned long mxs_mmc_setclock_mmc0(unsigned long hz)
{
- struct clk *ssp = clk_get(NULL, "ssp.0"), *parent;
-
- if (hz > 1000000)
- parent = clk_get(NULL, "ref_io.0");
- else
- parent = clk_get(NULL, "xtal.0");
+ struct clk *ssp = clk_get(NULL, "ssp.0");
- clk_set_parent(ssp, parent);
clk_set_rate(ssp, 2 * hz);
- clk_put(parent);
clk_put(ssp);
return hz;
@@ -583,7 +613,11 @@ static struct mxs_mmc_platform_data mx23_mmc0_data = {
.hw_release = mxs_mmc_hw_release_mmc0,
.get_wp = mxs_mmc_get_wp_mmc0,
.cmd_pullup = mxs_mmc_cmd_pullup_mmc0,
- .setclock = mxs_mmc_setclock_mmc0,
+ /*
+ Don't change ssp clock because ssp1 and ssp2 share one ssp clock source
+ ssp module have own divider.
+ .setclock = mxs_mmc_setclock_mmc0,
+ */
.caps = MMC_CAP_4_BIT_DATA,
.min_clk = 400000,
.max_clk = 48000000,
@@ -636,6 +670,68 @@ static void mx23_init_mmc(void)
}
#endif
+#if defined(CONFIG_SPI_MXS) || defined(CONFIG_SPI_MXS_MODULE)
+static struct resource ssp1_resources[] = {
+ {
+ .start = SSP1_PHYS_ADDR,
+ .end = SSP1_PHYS_ADDR + 0x1FFF,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = IRQ_SSP1_DMA,
+ .end = IRQ_SSP1_DMA,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .start = IRQ_SSP_ERROR,
+ .end = IRQ_SSP_ERROR,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .start = MXS_DMA_CHANNEL_AHB_APBH_SSP1,
+ .end = MXS_DMA_CHANNEL_AHB_APBH_SSP1,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+static void __init mx23_init_spi1(void)
+{
+ struct platform_device *pdev;
+
+ pdev = mxs_get_device("mxs-spi", 0);
+ if (pdev == NULL || IS_ERR(pdev))
+ return;
+ pdev->resource = ssp1_resources;
+ pdev->num_resources = ARRAY_SIZE(ssp1_resources);
+
+ mxs_add_device(pdev, 3);
+}
+#else
+static void mx23_init_spi1(void)
+{
+ ;
+}
+#endif
+
+#define CMDLINE_DEVICE_CHOOSE(name, dev1, dev2) \
+ static char *cmdline_device_##name; \
+ static int cmdline_device_##name##_setup(char *dev) \
+ { \
+ cmdline_device_##name = dev + 1; \
+ return 0; \
+ } \
+ __setup(#name, cmdline_device_##name##_setup); \
+ void mx23_init_##name(void) \
+ { \
+ if (!cmdline_device_##name || \
+ !strcmp(cmdline_device_##name, #dev1)) \
+ mx23_init_##dev1(); \
+ else if (!strcmp(cmdline_device_##name, #dev2)) \
+ mx23_init_##dev2(); \
+ else \
+ pr_err("Unknown %s assignment '%s'.\n", \
+ #name, cmdline_device_##name); \
+ }
+
+CMDLINE_DEVICE_CHOOSE(ssp1, mmc, spi1)
+
#if defined(CONFIG_BATTERY_MXS)
/* battery info data */
static ddi_bc_Cfg_t battery_data = {
@@ -729,7 +825,7 @@ void __init mx23_init_spdif(void)
mxs_add_device(pdev, 3);
}
#else
-static inline mx23_init_spdif(void)
+static inline void mx23_init_spdif(void)
{
}
#endif
@@ -835,6 +931,49 @@ static void mx23_init_persistent()
}
#endif
+#if defined(CONFIG_FSL_OTP)
+/* Building up eight registers's names of a bank */
+#define BANK(a, b, c, d, e, f, g, h) \
+ {\
+ ("HW_OCOTP_"#a), ("HW_OCOTP_"#b), ("HW_OCOTP_"#c), ("HW_OCOTP_"#d), \
+ ("HW_OCOTP_"#e), ("HW_OCOTP_"#f), ("HW_OCOTP_"#g), ("HW_OCOTP_"#h) \
+ }
+
+#define BANKS (4)
+#define BANK_ITEMS (8)
+static const char *bank_reg_desc[BANKS][BANK_ITEMS] = {
+ BANK(CUST0, CUST1, CUST2, CUST3, CRYPTO0, CRYPTO1, CRYPTO2, CRYPTO3),
+ BANK(HWCAP0, HWCAP1, HWCAP2, HWCAP3, HWCAP4, HWCAP5, SWCAP, CUSTCAP),
+ BANK(LOCK, OPS0, OPS1, OPS2, OPS3, UN0, UN1, UN2),
+ BANK(ROM0, ROM1, ROM2, ROM3, ROM4, ROM5, ROM6, ROM7),
+};
+
+static struct fsl_otp_data otp_data = {
+ .fuse_name = (char **)bank_reg_desc,
+ .regulator_name = "vddio",
+ .fuse_num = BANKS * BANK_ITEMS,
+};
+#undef BANK
+#undef BANKS
+#undef BANK_ITEMS
+
+static void mx23_init_otp(void)
+{
+ struct platform_device *pdev;
+ pdev = mxs_get_device("ocotp", 0);
+ if (pdev == NULL || IS_ERR(pdev))
+ return;
+ pdev->dev.platform_data = &otp_data;
+ pdev->resource = NULL;
+ pdev->num_resources = 0;
+ mxs_add_device(pdev, 3);
+}
+#else
+static void mx23_init_otp(void)
+{
+}
+#endif
+
int __init mx23_device_init(void)
{
mx23_init_dma();
@@ -848,12 +987,14 @@ int __init mx23_device_init(void)
mx23_init_ts();
mx23_init_rtc();
mx23_init_dcp();
- mx23_init_mmc();
+ mx23_init_ssp1();
+ mx23_init_gpmi_nfc();
mx23_init_spdif();
mx23_init_lcdif();
mx23_init_pxp();
mx23_init_battery();
mx23_init_persistent();
+ mx23_init_otp();
return 0;
}
diff --git a/arch/arm/mach-mx23/emi.S b/arch/arm/mach-mx23/emi.S
index 5799ca23be8f..41e1ea6abe71 100644
--- a/arch/arm/mach-mx23/emi.S
+++ b/arch/arm/mach-mx23/emi.S
@@ -38,6 +38,8 @@
#define SCALING_DATA_NEW_FREQ_OFFSET 12
#define REGS_CLKCTRL_BASE MX23_SOC_IO_ADDRESS(CLKCTRL_PHYS_ADDR)
#define HW_CLKCTRL_EMI_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI)
+#define HW_CLKCTRL_FRAC_SET_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC_SET)
+#define HW_CLKCTRL_FRAC_CLR_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC_CLR)
#define HW_CLKCTRL_FRAC_ADDR (REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC)
#define HW_EMI_CTRL_ADDR MX23_SOC_IO_ADDRESS(REGS_EMI_PHYS + HW_EMI_CTRL)
#define HW_DRAM_CTL04_ADDR MX23_SOC_IO_ADDRESS(REGS_DRAM_PHYS + HW_DRAM_CTL04)
@@ -72,53 +74,82 @@ ENTRY(mxs_ram_freq_scale)
beq 1b
nop
+
+ @ RAM to clk from xtal
+ mov r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF)
+ orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00)
+ orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000)
+ orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000)
+ mov r1, #(1<<6)
+ str r1, [r0, #4]
+ mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF)
+ orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00)
+ orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000)
+ orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000)
+101: ldr r1, [r0]
+ tst r1, #BM_CLKCTRL_EMI_BUSY_REF_XTAL
+ bne 101b
+
+ @ Gate ref_emi
+ mov r0, #(HW_CLKCTRL_FRAC_SET_ADDR & 0x000000FF)
+ orr r0, r0, #(HW_CLKCTRL_FRAC_SET_ADDR & 0x0000FF00)
+ orr r0, r0, #(HW_CLKCTRL_FRAC_SET_ADDR & 0x00FF0000)
+ orr r0, r0, #(HW_CLKCTRL_FRAC_SET_ADDR & 0xFF000000)
+
+ mov r1, #(BM_CLKCTRL_FRAC_CLKGATEEMI)
+ str r1, [r0]
+
+
@ prepare for change
cmp r5, #24
bgt 2f
bl mx23_ram_24M_set_timings
- b 100f
+ b 44f
2: cmp r5, #48
bgt 3f
bl mx23_ram_48M_set_timings
- b 100f
+ b 55f
3: cmp r5, #60
bgt 4f
bl mx23_ram_60M_set_timings
- b 100f
+ b 55f
4: cmp r5, #80
bgt 5f
bl mx23_ram_80M_set_timings
- b 100f
+ b 55f
5: cmp r5, #96
bgt 6f
bl mx23_ram_96M_set_timings
- b 100f
+ b 55f
6: cmp r5, #120
bgt 7f
bl mx23_ram_120M_set_timings
- b 100f
+ b 55f
7: cmp r5, #133
bgt 8f
bl mx23_ram_133M_set_timings
- b 100f
+ b 55f
8: bl mx23_ram_150M_set_timings
-100:
- @ RAM to clk from xtal
- mov r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF)
- orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00)
- orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000)
- orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000)
- mov r1, #(1<<6)
- str r1, [r0, #4]
- mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF)
- orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00)
- orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000)
- orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000)
-101: ldr r1, [r0]
- tst r1, #BM_CLKCTRL_EMI_BUSY_REF_XTAL
- bne 101b
+44:
+
+ bl __mx23_emi_set_values_xtal
+
+ @ resttore normal DRAM mode
+ ldr r0, __mx23_dram_ctl00
+ ldr r1, [r0, #0x20]
+ bic r1, r1, #(1 << 8)
+ str r1, [r0, #0x20]
+
+ @ wait for it to actually happen
+ ldr r0, __mx23_dram_emi00
+99: ldr r1, [r0, #0x10]
+ tst r1, #(1 << 1)
+ bne 99b
+ b 110f
+
+55:
@When are using the DLL, reset the DRAM controller and DLL
@start point logic (via DLL_SHIFT_RESET and DLL_RESET).
@After changing clock dividers and loading
@@ -136,14 +167,15 @@ ENTRY(mxs_ram_freq_scale)
orr r1, r1, #BM_EMI_CTRL_DLL_RESET
str r1, [r0] @write back values to HW_EMI_CTRL register.
- bl __mx23_emi_set_values
+ bl __mx23_emi_set_values2
@ EMI back to PLL
mov r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x000000FF)
orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x0000FF00)
orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0x00FF0000)
orr r0, r0, #(HW_CLKCTRL_CLKSEQ_ADDR & 0xFF000000)
- mov r1, #(1<<6)
+ mov r1, #(BM_CLKCTRL_CLKSEQ_BYPASS_EMI)
+ @clear bypass bit
str r1, [r0, #8]
@ Wait for BUSY_REF_EMI, to assure new clock dividers
@@ -179,16 +211,6 @@ ENTRY(mxs_ram_freq_scale)
bic r1, #BM_EMI_CTRL_DLL_RESET
str r1, [r0]
-@Wait for BUSY_REF_EMI, to assure new clock dividers are done transferring.
-@(\todo is that necessary. we already did this above.
- mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF)
- orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00)
- orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000)
- orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000)
-66: ldr r1, [r0]
- tst r1, #BM_CLKCTRL_EMI_BUSY_REF_EMI
- bne 66b
-
@ Wait for DLL locking.
@ while(HW_DRAM_CTL04.B.DLLLOCKREG==0);
@@ -200,7 +222,7 @@ ENTRY(mxs_ram_freq_scale)
tst r1, #BM_DRAM_CTL04_DLLLOCKREG
beq 77b
-
+88:
@ resttore normal DRAM mode
ldr r0, __mx23_dram_ctl00
ldr r1, [r0, #0x20]
@@ -213,6 +235,7 @@ ENTRY(mxs_ram_freq_scale)
tst r1, #(1 << 1)
bne 102b
+110:
@ restore regs and return
ldmfd sp!, {r1 - r9, lr}
mov pc, lr
diff --git a/arch/arm/mach-mx23/emi.inc b/arch/arm/mach-mx23/emi.inc
index 194181f9f753..290d35ed2729 100644
--- a/arch/arm/mach-mx23/emi.inc
+++ b/arch/arm/mach-mx23/emi.inc
@@ -20,15 +20,38 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-__mx23_emi_set_values:
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+
+__mx23_emi_set_values_xtal:
stmfd r9!, {r0 - r4, lr}
+
mov r1, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF)
orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00)
orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000)
orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000)
-@ DDC_RESNCY is deprecated at mx23
-@ mov r3, #BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE
+32: ldr r4, [r1]
+ tst r4, #BM_CLKCTRL_EMI_BUSY_REF_XTAL
+ bne 32b
+ b 4f
+
+__mx23_emi_set_values2:
+
+ stmfd r9!, {r0 - r4, lr}
+
+ mov r1, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF)
+ orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00)
+ orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000)
+ orr r1, r1, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000)
mov r0, #(HW_CLKCTRL_FRAC_ADDR & 0x000000FF)
orr r0, r0, #(HW_CLKCTRL_FRAC_ADDR & 0x0000FF00)
@@ -36,17 +59,34 @@ __mx23_emi_set_values:
orr r0, r0, #(HW_CLKCTRL_FRAC_ADDR & 0xFF000000)
ldr r2, [r0]
- and r4, r2, #BM_CLKCTRL_FRAC_EMIFRAC
- lsr r4, r4, #8
- /* new pll div > cur pll div? */
- cmp r4, r8
- bgt 1f
+ @clear EMIFRAC bits and store result in r4
bic r4, r2, #BM_CLKCTRL_FRAC_EMIFRAC
- orr r4, r4, r8, lsl #8
- str r4, [r0]
- nop
- nop
- nop
+
+ orr r4, r4, r8, lsl #BP_CLKCTRL_FRAC_EMIFRAC
+ str r4, [r0]
+
+ @ ungate ref_emi
+ mov r0, #(HW_CLKCTRL_FRAC_CLR_ADDR & 0x000000FF)
+ orr r0, r0, #(HW_CLKCTRL_FRAC_CLR_ADDR & 0x0000FF00)
+ orr r0, r0, #(HW_CLKCTRL_FRAC_CLR_ADDR & 0x00FF0000)
+ orr r0, r0, #(HW_CLKCTRL_FRAC_CLR_ADDR & 0xFF000000)
+
+ mov r2, #(BM_CLKCTRL_FRAC_CLKGATEEMI)
+ str r2, [r0]
+
+
+ @ set the integer divider
+ ldr r2, [r1]
+ bic r2, r2, #BM_CLKCTRL_EMI_DIV_EMI
+ orr r2, r2, r7, lsl #BP_CLKCTRL_EMI_DIV_EMI
+
+ str r2, [r1]
+
+ @ wait for clock to stabilize
+50: ldr r2, [r1]
+ tst r2, #BM_CLKCTRL_EMI_BUSY_REF_EMI
+ bne 50b
+ b 4f
@ Change integer/fractional dividers.
@@ -103,8 +143,6 @@ __mx23_emi_set_values:
31: ldr r4, [r1]
tst r4, #BM_CLKCTRL_EMI_BUSY_REF_EMI
bne 31b
- tst r4, #BM_CLKCTRL_EMI_BUSY_REF_XTAL
- bne 31b
4: ldmfd r9!, {r0 - r4, lr}
mov pc, lr
diff --git a/arch/arm/mach-mx23/include/mach/lcdif.h b/arch/arm/mach-mx23/include/mach/lcdif.h
index f0ee0d5e5c1a..f12802087320 100644
--- a/arch/arm/mach-mx23/include/mach/lcdif.h
+++ b/arch/arm/mach-mx23/include/mach/lcdif.h
@@ -201,10 +201,10 @@ static inline void setup_dotclk_panel(u16 v_pulse_width,
BM_LCDIF_CTRL_INPUT_DATA_SWIZZLE |
BM_LCDIF_CTRL_LCD_DATABUS_WIDTH,
REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR);
- __raw_writel(BF_LCDIF_CTRL_WORD_LENGTH(3) | /* 24 bit */
- BM_LCDIF_CTRL_DATA_SELECT | /* data mode */
- BF_LCDIF_CTRL_INPUT_DATA_SWIZZLE(0) | /* no swap */
- BF_LCDIF_CTRL_LCD_DATABUS_WIDTH(3), /* 24 bit */
+ __raw_writel(BF_LCDIF_CTRL_WORD_LENGTH(3) |/* 24 bit */
+ BM_LCDIF_CTRL_DATA_SELECT |/* data mode */
+ BF_LCDIF_CTRL_INPUT_DATA_SWIZZLE(0) |/* no swap */
+ BF_LCDIF_CTRL_LCD_DATABUS_WIDTH(3),/* 24 bit */
REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET);
val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_VDCTRL0);
@@ -275,4 +275,167 @@ static inline void release_dotclk_panel(void)
__raw_writel(0, REGS_LCDIF_BASE + HW_LCDIF_VDCTRL3);
}
+static inline void setup_dvi_panel(u16 h_active, u16 v_active,
+ u16 h_blanking, u16 v_lines,
+ u16 v1_blank_start, u16 v1_blank_end,
+ u16 v2_blank_start, u16 v2_blank_end,
+ u16 f1_start, u16 f1_end,
+ u16 f2_start, u16 f2_end)
+{
+ u32 val;
+ /* 32bit packed format (RGB) */
+ __raw_writel(BM_LCDIF_CTRL1_BYTE_PACKING_FORMAT,
+ REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR);
+ __raw_writel(BF_LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x7) |
+ BM_LCDIF_CTRL1_RECOVER_ON_UNDERFLOW,
+ REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET);
+
+ val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_TRANSFER_COUNT);
+ val &= ~(BM_LCDIF_TRANSFER_COUNT_V_COUNT |
+ BM_LCDIF_TRANSFER_COUNT_H_COUNT);
+ val |= BF_LCDIF_TRANSFER_COUNT_H_COUNT(h_active) |
+ BF_LCDIF_TRANSFER_COUNT_V_COUNT(v_active);
+ __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_TRANSFER_COUNT);
+
+ /* set lcdif to DVI mode */
+ __raw_writel(BM_LCDIF_CTRL_DVI_MODE,
+ REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET);
+ __raw_writel(BM_LCDIF_CTRL_VSYNC_MODE,
+ REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR);
+ __raw_writel(BM_LCDIF_CTRL_DOTCLK_MODE,
+ REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR);
+
+ __raw_writel(BM_LCDIF_CTRL_BYPASS_COUNT,
+ REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET);
+ /* convert input RGB -> YCbCr */
+ __raw_writel(BM_LCDIF_CTRL_RGB_TO_YCBCR422_CSC,
+ REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET);
+ /* interlace odd and even fields */
+ __raw_writel(BM_LCDIF_CTRL1_INTERLACE_FIELDS,
+ REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET);
+
+ __raw_writel(BM_LCDIF_CTRL_WORD_LENGTH |
+ BM_LCDIF_CTRL_INPUT_DATA_SWIZZLE |
+ BM_LCDIF_CTRL_LCD_DATABUS_WIDTH,
+ REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR);
+ __raw_writel(BF_LCDIF_CTRL_WORD_LENGTH(3) | /* 24 bit */
+ BM_LCDIF_CTRL_DATA_SELECT | /* data mode */
+ BF_LCDIF_CTRL_INPUT_DATA_SWIZZLE(0) | /* no swap */
+ BF_LCDIF_CTRL_LCD_DATABUS_WIDTH(1), /* 8 bit */
+ REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET);
+
+ /* LCDIF_DVI */
+ /* set frame size */
+ val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL0);
+ val &= ~(BM_LCDIF_DVICTRL0_H_ACTIVE_CNT |
+ BM_LCDIF_DVICTRL0_H_BLANKING_CNT |
+ BM_LCDIF_DVICTRL0_V_LINES_CNT);
+ val |= BF_LCDIF_DVICTRL0_H_ACTIVE_CNT(1440) |
+ BF_LCDIF_DVICTRL0_H_BLANKING_CNT(h_blanking) |
+ BF_LCDIF_DVICTRL0_V_LINES_CNT(v_lines);
+ __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL0);
+
+ /* set start/end of field-1 and start of field-2 */
+ val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL1);
+ val &= ~(BM_LCDIF_DVICTRL1_F1_START_LINE |
+ BM_LCDIF_DVICTRL1_F1_END_LINE |
+ BM_LCDIF_DVICTRL1_F2_START_LINE);
+ val |= BF_LCDIF_DVICTRL1_F1_START_LINE(f1_start) |
+ BF_LCDIF_DVICTRL1_F1_END_LINE(f1_end) |
+ BF_LCDIF_DVICTRL1_F2_START_LINE(f2_start);
+ __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL1);
+
+ /* set first vertical blanking interval and end of filed-2 */
+ val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL2);
+ val &= ~(BM_LCDIF_DVICTRL2_F2_END_LINE |
+ BM_LCDIF_DVICTRL2_V1_BLANK_START_LINE |
+ BM_LCDIF_DVICTRL2_V1_BLANK_END_LINE);
+ val |= BF_LCDIF_DVICTRL2_F2_END_LINE(f2_end) |
+ BF_LCDIF_DVICTRL2_V1_BLANK_START_LINE(v1_blank_start) |
+ BF_LCDIF_DVICTRL2_V1_BLANK_END_LINE(v1_blank_end);
+ __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL2);
+
+ /* set second vertical blanking interval */
+ val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL3);
+ val &= ~(BM_LCDIF_DVICTRL3_V2_BLANK_START_LINE |
+ BM_LCDIF_DVICTRL3_V2_BLANK_END_LINE);
+ val |= BF_LCDIF_DVICTRL3_V2_BLANK_START_LINE(v2_blank_start) |
+ BF_LCDIF_DVICTRL3_V2_BLANK_END_LINE(v2_blank_end);
+ __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL3);
+
+ /* fill the rest area black color if the input frame
+ * is not 720 pixels/line
+ */
+ if (h_active != 720) {
+ /* the input frame can't be less then (720-256) pixels/line */
+ if (720 - h_active > 0xff)
+ h_active = 720 - 0xff;
+
+ val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_DVICTRL4);
+ val &= ~(BM_LCDIF_DVICTRL4_H_FILL_CNT |
+ BM_LCDIF_DVICTRL4_Y_FILL_VALUE |
+ BM_LCDIF_DVICTRL4_CB_FILL_VALUE |
+ BM_LCDIF_DVICTRL4_CR_FILL_VALUE);
+ val |= BF_LCDIF_DVICTRL4_H_FILL_CNT(720 - h_active) |
+ BF_LCDIF_DVICTRL4_Y_FILL_VALUE(16) |
+ BF_LCDIF_DVICTRL4_CB_FILL_VALUE(128) |
+ BF_LCDIF_DVICTRL4_CR_FILL_VALUE(128);
+ __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_DVICTRL4);
+ }
+
+ /* Color Space Conversion RGB->YCbCr */
+ val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF0);
+ val &= ~(BM_LCDIF_CSC_COEFF0_C0 |
+ BM_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER);
+ val |= BF_LCDIF_CSC_COEFF0_C0(0x41) |
+ BF_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER(3);
+ __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF0);
+
+ val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF1);
+ val &= ~(BM_LCDIF_CSC_COEFF1_C1 | BM_LCDIF_CSC_COEFF1_C2);
+ val |= BF_LCDIF_CSC_COEFF1_C1(0x81) |
+ BF_LCDIF_CSC_COEFF1_C2(0x19);
+ __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF1);
+
+ val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF2);
+ val &= ~(BM_LCDIF_CSC_COEFF2_C3 | BM_LCDIF_CSC_COEFF2_C4);
+ val |= BF_LCDIF_CSC_COEFF2_C3(0x3DB) |
+ BF_LCDIF_CSC_COEFF2_C4(0x3B6);
+ __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF2);
+
+ val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF3);
+ val &= ~(BM_LCDIF_CSC_COEFF3_C5 | BM_LCDIF_CSC_COEFF3_C6);
+ val |= BF_LCDIF_CSC_COEFF3_C5(0x70) |
+ BF_LCDIF_CSC_COEFF3_C6(0x70);
+ __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF3);
+
+ val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF4);
+ val &= ~(BM_LCDIF_CSC_COEFF4_C7 | BM_LCDIF_CSC_COEFF4_C8);
+ val |= BF_LCDIF_CSC_COEFF4_C7(0x3A2) | BF_LCDIF_CSC_COEFF4_C8(0x3EE);
+ __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_COEFF4);
+
+ val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_OFFSET);
+ val &= ~(BM_LCDIF_CSC_OFFSET_CBCR_OFFSET
+ | BM_LCDIF_CSC_OFFSET_Y_OFFSET);
+ val |= BF_LCDIF_CSC_OFFSET_CBCR_OFFSET(0x80) |
+ BF_LCDIF_CSC_OFFSET_Y_OFFSET(0x10);
+ __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_OFFSET);
+
+ val = __raw_readl(REGS_LCDIF_BASE + HW_LCDIF_CSC_LIMIT);
+ val &= ~(BM_LCDIF_CSC_LIMIT_CBCR_MIN |
+ BM_LCDIF_CSC_LIMIT_CBCR_MAX |
+ BM_LCDIF_CSC_LIMIT_Y_MIN |
+ BM_LCDIF_CSC_LIMIT_Y_MAX);
+ val |= BF_LCDIF_CSC_LIMIT_CBCR_MIN(16) |
+ BF_LCDIF_CSC_LIMIT_CBCR_MAX(240) |
+ BF_LCDIF_CSC_LIMIT_Y_MIN(16) |
+ BF_LCDIF_CSC_LIMIT_Y_MAX(235);
+ __raw_writel(val, REGS_LCDIF_BASE + HW_LCDIF_CSC_LIMIT);
+}
+
+static inline void release_dvi_panel(void)
+{
+ __raw_writel(BM_LCDIF_CTRL_DVI_MODE,
+ REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR);
+}
#endif /* _ARCH_ARM_LCDIF_H */
diff --git a/arch/arm/mach-mx23/include/mach/mx23.h b/arch/arm/mach-mx23/include/mach/mx23.h
index 09269524a4f0..6e1d2aa7106e 100644
--- a/arch/arm/mach-mx23/include/mach/mx23.h
+++ b/arch/arm/mach-mx23/include/mach/mx23.h
@@ -50,6 +50,7 @@
#define OCOTP_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x02C000)
#define AXI_AHB0_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x02E000)
#define LCDIF_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x030000)
+#define TVENC_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x038000)
#define CLKCTRL_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x040000)
#define SAIF0_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x042000)
#define POWER_PHYS_ADDR (MX23_SOC_IO_PHYS_BASE + 0x044000)
@@ -72,12 +73,17 @@
#define MX23_SOC_IO_ADDRESS(x) \
((x) - MX23_SOC_IO_PHYS_BASE + MX23_SOC_IO_VIRT_BASE)
+#ifdef __ASSEMBLER__
+#define IO_ADDRESS(x) \
+ MX23_SOC_IO_ADDRESS(x)
+#else
#define IO_ADDRESS(x) \
(void __force __iomem *) \
(((x) >= (unsigned long)MX23_SOC_IO_PHYS_BASE) && \
((x) < (unsigned long)MX23_SOC_IO_PHYS_BASE + \
MX23_SOC_IO_AREA_SIZE) ? \
MX23_SOC_IO_ADDRESS(x) : 0xDEADBEEF)
+#endif
#ifdef CONFIG_MXS_EARLY_CONSOLE
#define MXS_DEBUG_CONSOLE_PHYS DUART_PHYS_ADDR
diff --git a/arch/arm/mach-mx23/mx23_pins.h b/arch/arm/mach-mx23/mx23_pins.h
index 4659315e29f6..9811bfdd0cad 100644
--- a/arch/arm/mach-mx23/mx23_pins.h
+++ b/arch/arm/mach-mx23/mx23_pins.h
@@ -47,7 +47,7 @@
#define PINID_GPMI_D15 MXS_PIN_ENCODE(0, 15)
#define PINID_GPMI_CLE MXS_PIN_ENCODE(0, 16)
#define PINID_GPMI_ALE MXS_PIN_ENCODE(0, 17)
-#define PINID_GMPI_CE2N MXS_PIN_ENCODE(0, 18)
+#define PINID_GPMI_CE2N MXS_PIN_ENCODE(0, 18)
#define PINID_GPMI_RDY0 MXS_PIN_ENCODE(0, 19)
#define PINID_GPMI_RDY1 MXS_PIN_ENCODE(0, 20)
#define PINID_GPMI_RDY2 MXS_PIN_ENCODE(0, 21)
diff --git a/arch/arm/mach-mx23/mx23evk.c b/arch/arm/mach-mx23/mx23evk.c
index 53f958779c1c..6ce1583e28eb 100644
--- a/arch/arm/mach-mx23/mx23evk.c
+++ b/arch/arm/mach-mx23/mx23evk.c
@@ -22,6 +22,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
+#include <linux/spi/spi.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
@@ -30,6 +31,7 @@
#include <mach/hardware.h>
#include <mach/device.h>
#include <mach/pinctrl.h>
+#include <mach/regs-ocotp.h>
#include "device.h"
#include "mx23evk.h"
@@ -58,6 +60,28 @@ static void i2c_device_init(void)
i2c_register_board_info(0, &mma7450_i2c_device, 1);
}
+static struct mxs_spi_platform_data enc_data = {
+ .hw_pin_init = mxs_spi_enc_pin_init,
+ .hw_pin_release = mxs_spi_enc_pin_release,
+};
+static struct spi_board_info spi_board_info[] __initdata = {
+#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE)
+ {
+ .modalias = "enc28j60",
+ .max_speed_hz = 6 * 1000 * 1000,
+ .bus_num = 1,
+ .chip_select = 0,
+ .platform_data = &enc_data,
+ },
+#endif
+};
+
+static void spi_device_init(void)
+{
+ spi_board_info[0].irq = gpio_to_irq(MXS_PIN_TO_GPIO(PINID_SSP1_DATA1));
+ spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+}
+
static void __init fixup_board(struct machine_desc *desc, struct tag *tags,
char **cmdline, struct meminfo *mi)
{
@@ -80,11 +104,23 @@ static void __init mx23evk_init_adc(void)
}
#endif
+#define REGS_OCOTP_BASE IO_ADDRESS(OCOTP_PHYS_ADDR)
+int get_evk_board_version()
+{
+ int boardid;
+ boardid = __raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CUSTCAP);
+ boardid &= 0x30000000;
+ boardid = boardid >> 28;
+
+ return boardid;
+}
+EXPORT_SYMBOL_GPL(get_evk_board_version);
static void __init mx23evk_device_init(void)
{
/* Add mx23evk special code */
i2c_device_init();
+ spi_device_init();
mx23evk_init_adc();
}
@@ -94,7 +130,12 @@ static void __init mx23evk_init_machine(void)
mx23_pinctrl_init();
/* Init iram allocate */
+#ifdef CONFIG_VECTORS_PHY_ADDR
+ /* reserve the first page for irq vectors table*/
+ iram_init(MX23_OCRAM_PHBASE + PAGE_SIZE, MX23_OCRAM_SIZE - PAGE_SIZE);
+#else
iram_init(MX23_OCRAM_PHBASE, MX23_OCRAM_SIZE);
+#endif
mx23_gpio_init();
mx23evk_pins_init();
diff --git a/arch/arm/mach-mx23/mx23evk.h b/arch/arm/mach-mx23/mx23evk.h
index afe7bcf4ffe1..ea2ab4def477 100644
--- a/arch/arm/mach-mx23/mx23evk.h
+++ b/arch/arm/mach-mx23/mx23evk.h
@@ -22,5 +22,11 @@
extern void __init mx23evk_pins_init(void);
extern void mx23evk_mma7450_pin_init(void);
extern int mx23evk_mma7450_pin_release(void);
+extern int mxs_spi_enc_pin_init(void);
+extern int mxs_spi_enc_pin_release(void);
+extern int mxs_mmc_get_wp_mmc0(void);
+extern int mxs_mmc_hw_init_mmc0(void);
+extern void mxs_mmc_hw_release_mmc0(void);
+extern void mxs_mmc_cmd_pullup_mmc0(int enable);
#endif /* __ASM_ARM_MACH_MX23EVK_H */
diff --git a/arch/arm/mach-mx23/mx23evk_pins.c b/arch/arm/mach-mx23/mx23evk_pins.c
index 5e60a2b1e387..cdf86cfbea63 100644
--- a/arch/arm/mach-mx23/mx23evk_pins.c
+++ b/arch/arm/mach-mx23/mx23evk_pins.c
@@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/gpio.h>
+#include <linux/delay.h>
#include <mach/pinctrl.h>
@@ -60,6 +61,28 @@ static struct pin_desc mx23evk_fixed_pins[] = {
},
#endif
+#ifdef CONFIG_MXS_AUART2_DEVICE_ENABLE
+ {
+ .name = "AUART2.RX",
+ .id = PINID_GPMI_D14,
+ .fun = PIN_FUN2,
+ },
+ {
+ .name = "AUART2.TX",
+ .id = PINID_GPMI_D15,
+ .fun = PIN_FUN2,
+ },
+ {
+ .name = "AUART2.CTS",
+ .id = PINID_ROTARYB,
+ .fun = PIN_FUN2,
+ },
+ {
+ .name = "AUART2.RTS",
+ .id = PINID_ROTARYA,
+ .fun = PIN_FUN2,
+ },
+#endif
#if defined(CONFIG_I2C_MXS) || \
defined(CONFIG_I2C_MXS_MODULE)
{
@@ -321,79 +344,6 @@ static struct pin_desc mx23evk_fixed_pins[] = {
.drive = 1,
},
#endif
-#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE)
- /* Configurations of SSP0 SD/MMC port pins */
- {
- .name = "SSP1_DATA0",
- .id = PINID_SSP1_DATA0,
- .fun = PIN_FUN1,
- .strength = PAD_8MA,
- .voltage = PAD_3_3V,
- .pullup = 1,
- .drive = 1,
- .pull = 1,
- },
- {
- .name = "SSP1_DATA1",
- .id = PINID_SSP1_DATA1,
- .fun = PIN_FUN1,
- .strength = PAD_8MA,
- .voltage = PAD_3_3V,
- .pullup = 1,
- .drive = 1,
- .pull = 1,
- },
- {
- .name = "SSP1_DATA2",
- .id = PINID_SSP1_DATA2,
- .fun = PIN_FUN1,
- .strength = PAD_8MA,
- .voltage = PAD_3_3V,
- .pullup = 1,
- .drive = 1,
- .pull = 1,
- },
- {
- .name = "SSP1_DATA3",
- .id = PINID_SSP1_DATA3,
- .fun = PIN_FUN1,
- .strength = PAD_8MA,
- .voltage = PAD_3_3V,
- .pullup = 1,
- .drive = 1,
- .pull = 1,
- },
- {
- .name = "SSP1_CMD",
- .id = PINID_SSP1_CMD,
- .fun = PIN_FUN1,
- .strength = PAD_8MA,
- .voltage = PAD_3_3V,
- .pullup = 1,
- .drive = 1,
- .pull = 1,
- },
- {
- .name = "SSP1_DETECT",
- .id = PINID_SSP1_DETECT,
- .fun = PIN_FUN1,
- .strength = PAD_8MA,
- .voltage = PAD_3_3V,
- .pullup = 0,
- .drive = 1,
- .pull = 0,
- },
- {
- .name = "SSP1_SCK",
- .id = PINID_SSP1_SCK,
- .fun = PIN_FUN1,
- .strength = PAD_8MA,
- .voltage = PAD_3_3V,
- .pullup = 0,
- .drive = 1,
- .pull = 0,
- },
-#endif
#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)
{
@@ -510,8 +460,323 @@ static struct pin_desc mx23evk_fixed_pins[] = {
.pull = 1,
},
#endif
+
+#if defined(CONFIG_MTD_NAND_GPMI_NFC) || \
+ defined(CONFIG_MTD_NAND_GPMI_NFC_MODULE)
+ {
+ .name = "GPMI D0",
+ .id = PINID_GPMI_D00,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI D1",
+ .id = PINID_GPMI_D01,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI D2",
+ .id = PINID_GPMI_D02,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI D3",
+ .id = PINID_GPMI_D03,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI D4",
+ .id = PINID_GPMI_D04,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI D5",
+ .id = PINID_GPMI_D05,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI D6",
+ .id = PINID_GPMI_D06,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI D7",
+ .id = PINID_GPMI_D07,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI CLE",
+ .id = PINID_GPMI_CLE,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI ALE",
+ .id = PINID_GPMI_ALE,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI WPN-",
+ .id = PINID_GPMI_WPN,
+ .fun = PIN_FUN1,
+ .strength = PAD_12MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI WR-",
+ .id = PINID_GPMI_WRN,
+ .fun = PIN_FUN1,
+ .strength = PAD_12MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI RD-",
+ .id = PINID_GPMI_RDN,
+ .fun = PIN_FUN1,
+ .strength = PAD_12MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI RDY0",
+ .id = PINID_GPMI_RDY0,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI RDY1",
+ .id = PINID_GPMI_RDY1,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI CE0-",
+ .id = PINID_GPMI_CE0N,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+ {
+ .name = "GPMI CE1-",
+ .id = PINID_GPMI_CE1N,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = !0
+ },
+#endif
+
};
+#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE)
+static struct pin_desc mx23evk_mmc_pins[] = {
+ /* Configurations of SSP0 SD/MMC port pins */
+ {
+ .name = "SSP1_DATA0",
+ .id = PINID_SSP1_DATA0,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP1_DATA1",
+ .id = PINID_SSP1_DATA1,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP1_DATA2",
+ .id = PINID_SSP1_DATA2,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP1_DATA3",
+ .id = PINID_SSP1_DATA3,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP1_CMD",
+ .id = PINID_SSP1_CMD,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SSP1_DETECT",
+ .id = PINID_SSP1_DETECT,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = 1,
+ .pull = 0,
+ },
+ {
+ .name = "SSP1_SCK",
+ .id = PINID_SSP1_SCK,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 0,
+ .drive = 1,
+ .pull = 0,
+ },
+};
+#endif
+
+#if defined(CONFIG_SPI_MXS) || defined(CONFIG_SPI_MXS_MODULE)
+static struct pin_desc mx23evk_spi_pins[] = {
+ {
+ .name = "SSP1_DATA0",
+ .id = PINID_SSP1_DATA0,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .drive = 1,
+ },
+ {
+ .name = "SSP1_DATA3",
+ .id = PINID_SSP1_DATA3,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .drive = 1,
+ },
+ {
+ .name = "SSP1_CMD",
+ .id = PINID_SSP1_CMD,
+ .fun = PIN_FUN1,
+ .strength = PAD_4MA,
+ .voltage = PAD_3_3V,
+ .drive = 1,
+ },
+ {
+ .name = "SSP1_SCK",
+ .id = PINID_SSP1_SCK,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .drive = 1,
+ },
+};
+#endif
+
+
+static void mxs_request_pins(struct pin_desc *pins, int nr)
+{
+ int i;
+ struct pin_desc *pin;
+
+ /* configure the pins */
+ for (i = 0; i < nr; i++) {
+ pin = &pins[i];
+ if (pin->fun == PIN_GPIO)
+ gpio_request(MXS_PIN_TO_GPIO(pin->id), pin->name);
+ else
+ mxs_request_pin(pin->id, pin->fun, pin->name);
+ if (pin->drive) {
+ mxs_set_strength(pin->id, pin->strength, pin->name);
+ mxs_set_voltage(pin->id, pin->voltage, pin->name);
+ }
+ if (pin->pull)
+ mxs_set_pullup(pin->id, pin->pullup, pin->name);
+ if (pin->fun == PIN_GPIO) {
+ if (pin->output)
+ gpio_direction_output(MXS_PIN_TO_GPIO(pin->id),
+ pin->data);
+ else
+ gpio_direction_input(MXS_PIN_TO_GPIO(pin->id));
+ }
+ }
+}
+
+static void mxs_release_pins(struct pin_desc *pins, int nr)
+{
+ int i;
+ struct pin_desc *pin;
+
+ /* release the pins */
+ for (i = 0; i < nr; i++) {
+ pin = &pins[i];
+ if (pin->fun == PIN_GPIO)
+ gpio_free(MXS_PIN_TO_GPIO(pin->id));
+ else
+ mxs_release_pin(pin->id, pin->name);
+ }
+}
+
#if defined(CONFIG_MXC_MMA7450) || defined(CONFIG_MXC_MMA7450_MODULE)
int mx23evk_mma7450_pin_init(void)
{
@@ -537,6 +802,116 @@ int mx23evk_mma7450_pin_release(void)
}
#endif
+#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE)
+#define MMC0_POWER MXS_PIN_TO_GPIO(PINID_PWM3)
+#define MMC0_WP MXS_PIN_TO_GPIO(PINID_PWM4)
+
+int mxs_mmc_get_wp_mmc0(void)
+{
+ return gpio_get_value(MMC0_WP);
+}
+
+int mxs_mmc_hw_init_mmc0(void)
+{
+ int ret = 0;
+
+ mxs_request_pins(mx23evk_mmc_pins, ARRAY_SIZE(mx23evk_mmc_pins));
+
+ /* Configure write protect GPIO pin */
+ ret = gpio_request(MMC0_WP, "mmc0_wp");
+ if (ret) {
+ pr_err("wp\n");
+ goto out_wp;
+ }
+ gpio_set_value(MMC0_WP, 0);
+ gpio_direction_input(MMC0_WP);
+
+ /* Configure POWER pin as gpio to drive power to MMC slot */
+ ret = gpio_request(MMC0_POWER, "mmc0_power");
+ if (ret) {
+ pr_err("power\n");
+ goto out_power;
+ }
+ gpio_direction_output(MMC0_POWER, 0);
+ mdelay(100);
+
+ return 0;
+
+out_power:
+ gpio_free(MMC0_WP);
+out_wp:
+ mxs_release_pins(mx23evk_mmc_pins, ARRAY_SIZE(mx23evk_mmc_pins));
+ return ret;
+}
+
+void mxs_mmc_hw_release_mmc0(void)
+{
+ gpio_free(MMC0_POWER);
+ gpio_free(MMC0_WP);
+
+ mxs_release_pins(mx23evk_mmc_pins, ARRAY_SIZE(mx23evk_mmc_pins));
+}
+
+void mxs_mmc_cmd_pullup_mmc0(int enable)
+{
+ mxs_set_pullup(PINID_SSP1_CMD, enable, "mmc0_cmd");
+}
+#else
+int mxs_mmc_get_wp_mmc0(void)
+{
+ return 0;
+}
+int mxs_mmc_hw_init_mmc0(void)
+{
+ return 0;
+}
+
+void mxs_mmc_hw_release_mmc0(void)
+{
+}
+
+void mxs_mmc_cmd_pullup_mmc0(int enable)
+{
+}
+#endif
+
+#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE)
+int mxs_spi_enc_pin_init(void)
+{
+ unsigned gpio = MXS_PIN_TO_GPIO(PINID_SSP1_DATA1);
+
+ mxs_request_pins(mx23evk_spi_pins, ARRAY_SIZE(mx23evk_spi_pins));
+
+ gpio_request(gpio, "ENC28J60_INTR");
+ gpio_direction_input(gpio);
+ set_irq_type(gpio_to_irq(gpio), IRQ_TYPE_EDGE_FALLING);
+
+ return 0;
+}
+int mxs_spi_enc_pin_release(void)
+{
+ unsigned gpio = MXS_PIN_TO_GPIO(PINID_SSP1_DATA1);
+
+
+ gpio_free(gpio);
+ set_irq_type(gpio_to_irq(gpio), IRQ_TYPE_NONE);
+
+ /* release the pins */
+ mxs_release_pins(mx23evk_spi_pins, ARRAY_SIZE(mx23evk_spi_pins));
+
+ return 0;
+}
+#else
+int mxs_spi_enc_pin_init(void)
+{
+ return 0;
+}
+int mxs_spi_enc_pin_release(void)
+{
+ return 0;
+}
+#endif
+
#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)
int mx23evk_enet_gpio_init(void)
{
@@ -560,26 +935,5 @@ int mx23evk_enet_gpio_init(void)
void __init mx23evk_pins_init(void)
{
- int i;
- struct pin_desc *pin;
- for (i = 0; i < ARRAY_SIZE(mx23evk_fixed_pins); i++) {
- pin = &mx23evk_fixed_pins[i];
- if (pin->fun == PIN_GPIO)
- gpio_request(MXS_PIN_TO_GPIO(pin->id), pin->name);
- else
- mxs_request_pin(pin->id, pin->fun, pin->name);
- if (pin->drive) {
- mxs_set_strength(pin->id, pin->strength, pin->name);
- mxs_set_voltage(pin->id, pin->voltage, pin->name);
- }
- if (pin->pull)
- mxs_set_pullup(pin->id, pin->pullup, pin->name);
- if (pin->fun == PIN_GPIO) {
- if (pin->output)
- gpio_direction_output(MXS_PIN_TO_GPIO(pin->id),
- pin->data);
- else
- gpio_direction_input(MXS_PIN_TO_GPIO(pin->id));
- }
- }
+ mxs_request_pins(mx23evk_fixed_pins, ARRAY_SIZE(mx23evk_fixed_pins));
}
diff --git a/arch/arm/mach-mx23/pm.c b/arch/arm/mach-mx23/pm.c
index c44a81f94b5e..0538326f441c 100644
--- a/arch/arm/mach-mx23/pm.c
+++ b/arch/arm/mach-mx23/pm.c
@@ -280,6 +280,7 @@ static inline void do_standby(void)
}
local_fiq_disable();
+ mxs_nomatch_suspend_timer();
__raw_writel(BM_POWER_CTRL_ENIRQ_PSWITCH,
REGS_POWER_BASE + HW_POWER_CTRL_SET);
@@ -502,7 +503,6 @@ static suspend_state_t saved_state;
static int mx23_pm_begin(suspend_state_t state)
{
- mxs_nomatch_suspend_timer();
saved_state = state;
return 0;
}
diff --git a/arch/arm/mach-mx23/usb_dr.c b/arch/arm/mach-mx23/usb_dr.c
index 13f9a296909c..4c702ffcd07c 100644
--- a/arch/arm/mach-mx23/usb_dr.c
+++ b/arch/arm/mach-mx23/usb_dr.c
@@ -27,7 +27,7 @@
#include "usb.h"
#include "mx23_pins.h"
-#define USB_POWER_ENABLE MXS_PIN_TO_GPIO(PINID_GMPI_CE2N)
+#define USB_POWER_ENABLE MXS_PIN_TO_GPIO(PINID_GPMI_CE2N)
#define USB_ID_PIN MXS_PIN_TO_GPIO(PINID_ROTARYA)
static void usb_host_phy_resume(struct fsl_usb2_platform_data *plat)
@@ -64,7 +64,7 @@ static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = {
};
/*
- * resources
+ * OTG resources
*/
static struct resource otg_resources[] = {
[0] = {
@@ -84,6 +84,28 @@ static struct resource otg_resources[] = {
},
};
+/*
+ * UDC resources (same as OTG resource)
+ */
+static struct resource udc_resources[] = {
+ [0] = {
+ .start = (u32)USBCTRL_PHYS_ADDR,
+ .end = (u32)(USBCTRL_PHYS_ADDR + 0x1ff),
+ .flags = IORESOURCE_MEM,
+ },
+
+ [1] = {
+ .start = IRQ_USB_CTRL,
+ .flags = IORESOURCE_IRQ,
+ },
+
+ [2] = {
+ .start = IRQ_USB_WAKEUP,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+
static u64 dr_udc_dmamask = ~(u32) 0;
static void dr_udc_release(struct device *dev)
{
@@ -101,8 +123,8 @@ static struct platform_device dr_udc_device = {
.dma_mask = &dr_udc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
- .resource = otg_resources,
- .num_resources = ARRAY_SIZE(otg_resources),
+ .resource = udc_resources,
+ .num_resources = ARRAY_SIZE(udc_resources),
};
static u64 dr_otg_dmamask = ~(u32) 0;
@@ -167,5 +189,5 @@ void fsl_phy_set_power(struct fsl_xcvr_ops *this,
#ifdef CONFIG_MXS_VBUS_CURRENT_DRAW
fs_initcall(usb_dr_init);
#else
- module_init(usb_dr_init);
+ subsys_initcall(usb_dr_init);
#endif
diff --git a/arch/arm/mach-mx25/devices.c b/arch/arm/mach-mx25/devices.c
index 093e8e146f20..73ed01ab6b57 100644
--- a/arch/arm/mach-mx25/devices.c
+++ b/arch/arm/mach-mx25/devices.c
@@ -555,11 +555,58 @@ static inline void mxc_init_flexcan(void)
}
#endif
+#if defined(CONFIG_SND_MXC_SOC_ESAI) || defined(CONFIG_SND_MXC_SOC_ESAI_MODULE)
+
+static struct mxc_esai_platform_data esai_data = {
+ .activate_esai_ports = gpio_activate_esai_ports,
+ .deactivate_esai_ports = gpio_deactivate_esai_ports,
+};
+
+static struct resource esai_resources[] = {
+ {
+ .start = ESAI_BASE_ADDR,
+ .end = ESAI_BASE_ADDR + 0x100,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_ESAI,
+ .end = MXC_INT_ESAI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device mxc_esai_device = {
+ .name = "mxc_esai",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(esai_resources),
+ .resource = esai_resources,
+ .dev = {
+ .release = mxc_nop_release,
+ .platform_data = &esai_data,
+ },
+};
+
+static void mxc_init_esai(void)
+{
+ platform_device_register(&mxc_esai_device);
+}
+#else
+static void mxc_init_esai(void)
+{
+
+}
+#endif
+
+static struct mxc_audio_platform_data mxc_surround_audio_data = {
+ .ext_ram = 1,
+};
+
static struct platform_device mxc_alsa_surround_device = {
.name = "imx-3stack-wm8580",
.id = 0,
.dev = {
.release = mxc_nop_release,
+ .platform_data = &mxc_surround_audio_data,
},
};
@@ -670,7 +717,7 @@ static int __init mxc_init_devices(void)
mxc_init_flexcan();
mxc_init_iim();
mxc_init_ssi();
-
+ mxc_init_esai();
return 0;
}
diff --git a/arch/arm/mach-mx25/mx25_3stack.c b/arch/arm/mach-mx25/mx25_3stack.c
index 557447964d09..c73bcbf6371e 100644
--- a/arch/arm/mach-mx25/mx25_3stack.c
+++ b/arch/arm/mach-mx25/mx25_3stack.c
@@ -22,6 +22,7 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/smsc911x.h>
+#include <linux/fec.h>
#if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE)
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
@@ -100,13 +101,17 @@ static struct resource mxc_kpp_resources[] = {
.start = MXC_INT_KPP,
.end = MXC_INT_KPP,
.flags = IORESOURCE_IRQ,
- }
+ },
+ [1] = {
+ .start = KPP_BASE_ADDR,
+ .end = KPP_BASE_ADDR + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
};
static struct keypad_data keypad_plat_data = {
.rowmax = 4,
.colmax = 4,
- .irq = MXC_INT_KPP,
.learning = 0,
.delay = 2,
.matrix = keymapping,
@@ -161,6 +166,21 @@ static struct mtd_partition mxc_nand_partitions[] = {
.size = MTDPART_SIZ_FULL},
};
+static struct resource mxc_nand_resources[] = {
+ {
+ .flags = IORESOURCE_MEM,
+ .name = "NFC_AXI_BASE",
+ .start = NFC_BASE_ADDR,
+ .end = NFC_BASE_ADDR + SZ_8K - 1,
+ },
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = MXC_INT_NANDFC,
+ .end = MXC_INT_NANDFC,
+ },
+};
+
+
static struct flash_platform_data mxc_nand_data = {
.parts = mxc_nand_partitions,
.nr_parts = ARRAY_SIZE(mxc_nand_partitions),
@@ -174,6 +194,8 @@ static struct platform_device mxc_nand_mtd_device = {
.release = mxc_nop_release,
.platform_data = &mxc_nand_data,
},
+ .resource = mxc_nand_resources,
+ .num_resources = ARRAY_SIZE(mxc_nand_resources),
};
static void mxc_init_nand_mtd(void)
@@ -296,7 +318,7 @@ static struct spi_board_info mxc_spi_board_info[] __initdata = {
.max_speed_hz = 18000000,
.bus_num = 1,
.chip_select = 0,
- .mode = SPI_MODE_2,
+ .mode = SPI_MODE_0,
},
{
.modalias = "wm8580_spi",
@@ -458,9 +480,16 @@ static struct resource mxc_fec_resources[] = {
},
};
+static struct fec_platform_data fec_data = {
+ .phy = PHY_INTERFACE_MODE_RMII,
+};
+
struct platform_device mxc_fec_device = {
.name = "fec",
.id = 0,
+ .dev = {
+ .platform_data = &fec_data,
+ },
.num_resources = ARRAY_SIZE(mxc_fec_resources),
.resource = mxc_fec_resources,
};
diff --git a/arch/arm/mach-mx25/mx25_3stack_gpio.c b/arch/arm/mach-mx25/mx25_3stack_gpio.c
index 5f7dd4f63b06..23d9505e7941 100644
--- a/arch/arm/mach-mx25/mx25_3stack_gpio.c
+++ b/arch/arm/mach-mx25/mx25_3stack_gpio.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -1333,10 +1333,10 @@ void gpio_activate_audio_ports(void)
EXPORT_SYMBOL(gpio_activate_audio_ports);
/*!
- * This function inactivates DAM port 4 for
+ * This function deactivates DAM port 4 for
* audio I/O
*/
-void gpio_inactive_audio_ports(void)
+void gpio_deactive_audio_ports(void)
{
gpio_request(IOMUX_TO_GPIO(MX25_PIN_EB0), NULL); /*SSI4_STXD*/
gpio_request(IOMUX_TO_GPIO(MX25_PIN_EB1), NULL); /*SSI4_SRXD*/
@@ -1352,7 +1352,7 @@ void gpio_inactive_audio_ports(void)
mxc_free_iomux(MX25_PIN_A10, MUX_CONFIG_GPIO);
mxc_free_iomux(MX25_PIN_D13, MUX_CONFIG_GPIO);
}
-EXPORT_SYMBOL(gpio_inactive_audio_ports);
+EXPORT_SYMBOL(gpio_deactive_audio_ports);
int headphone_det_status(void)
{
diff --git a/arch/arm/mach-mx25/usb_dr.c b/arch/arm/mach-mx25/usb_dr.c
index b185d5cdeff5..b3d024cb06f8 100644
--- a/arch/arm/mach-mx25/usb_dr.c
+++ b/arch/arm/mach-mx25/usb_dr.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -39,7 +39,7 @@ static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = {
};
/*
- * resources
+ * OTG resources
*/
static struct resource otg_resources[] = {
[0] = {
@@ -53,6 +53,22 @@ static struct resource otg_resources[] = {
},
};
+/*
+ * UDC resources (same as OTG resource)
+ */
+static struct resource udc_resources[] = {
+ [0] = {
+ .start = (u32)(USB_OTGREGS_BASE),
+ .end = (u32)(USB_OTGREGS_BASE + 0x1ff),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = MXC_INT_USB_OTG,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+
static u64 dr_udc_dmamask = ~(u32) 0;
static void dr_udc_release(struct device *dev)
{
@@ -75,8 +91,8 @@ static struct platform_device __maybe_unused dr_udc_device = {
.dma_mask = &dr_udc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
- .resource = otg_resources,
- .num_resources = ARRAY_SIZE(otg_resources),
+ .resource = udc_resources,
+ .num_resources = ARRAY_SIZE(udc_resources),
};
static struct platform_device __maybe_unused dr_otg_device = {
diff --git a/arch/arm/mach-mx28/Kconfig b/arch/arm/mach-mx28/Kconfig
index fdca0f6900ca..cbbf45230472 100644
--- a/arch/arm/mach-mx28/Kconfig
+++ b/arch/arm/mach-mx28/Kconfig
@@ -9,4 +9,14 @@ config MACH_MX28EVK
config MXS_TIMER_WITH_MACH
bool "Timer with architecture."
+config MXS_TIMER_WITH_MACH
+ bool "System Timer support Compare Match interrupt"
+
endchoice
+
+config VECTORS_PHY_ADDR
+ int "vectors address"
+ default 0
+ help
+ This config set vectors table is located which physical address
+
diff --git a/arch/arm/mach-mx28/bus_freq.c b/arch/arm/mach-mx28/bus_freq.c
index a997eaa9a01f..ef01a41fc095 100644
--- a/arch/arm/mach-mx28/bus_freq.c
+++ b/arch/arm/mach-mx28/bus_freq.c
@@ -46,24 +46,19 @@
#define CLKCTRL_BASE_ADDR IO_ADDRESS(CLKCTRL_PHYS_ADDR)
#define DIGCTRL_BASE_ADDR IO_ADDRESS(DIGCTL_PHYS_ADDR)
-#define BP_CLKCTRL_HBUS_ASM_ENABLE 20
-#define CLKCTRL_PLL_PWD_BIT 17
-#define CLKCTRL_PLL_BYPASS 0x1ff
#define BF(value, field) (((value) << BP_##field) & BM_##field)
struct profile profiles[] = {
- { 454736, 151580, 196360, 0, 1550000,
- 1450000, 355000, 3300000, 1750000, 0 },
- { 392727, 130910, 160000, 0, 1475000,
- 1375000, 225000, 3300000, 1750000, 0 },
- { 360000, 120000, 130910, 0, 1375000,
- 1275000, 200000, 3300000, 1750000, 0 },
- { 261818, 130910, 130910, 0, 1275000,
- 1175000, 173000, 3300000, 1750000, 0 },
- { 64000, 64000, 130910, 3, 1050000,
- 975000, 150000, 3300000, 1750000, 0 },
+ { 454736, 151570, 205710, 0, 1550000,
+ 1450000, 355000, 3300000, 1750000, 24000, 0 },
+ { 360000, 120000, 130910, 0, 1350000,
+ 1250000, 200000, 3300000, 1750000, 24000, 0 },
+ { 261818, 130910, 130910, 0, 1350000,
+ 1250000, 173000, 3300000, 1750000, 24000, 0 },
+ { 64000, 64000, 130910, 3, 1350000,
+ 1250000, 150000, 3300000, 1750000, 24000, 0 },
{ 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0 },
+ 0, 0, 0, 0, 0, 0 },
};
static struct device *busfreq_dev;
@@ -82,58 +77,13 @@ int low_freq_used(void)
return 0;
}
-void hbus_auto_slow_mode_enable(void)
+int is_hclk_autoslow_ok(void)
{
- __raw_writel(BP_CLKCTRL_HBUS_ASM_ENABLE,
- CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_SET);
-}
-EXPORT_SYMBOL(hbus_auto_slow_mode_enable);
-
-void hbus_auto_slow_mode_disable(void)
-{
- __raw_writel(BP_CLKCTRL_HBUS_ASM_ENABLE,
- CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR);
-}
-EXPORT_SYMBOL(hbus_auto_slow_mode_disable);
-
-int cpu_clk_set_pll_on(struct clk *clk, unsigned int freq)
-{
- struct cpufreq_freqs freqs;
-
- freqs.old = clk_get_rate(clk);
- freqs.cpu = 0;
- freqs.new = freq;
-
- if (freqs.old == 24000 && freqs.new > 24000) {
- /* turn pll on */
- __raw_writel(CLKCTRL_PLL_PWD_BIT, CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_PLL0CTRL0_SET);
- udelay(10);
- } else if (freqs.old > 24000 && freqs.new == 24000)
- clkseq_setting = __raw_readl(CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_CLKSEQ);
- return 0;
-}
-
-int cpu_clk_set_pll_off(struct clk *clk, unsigned int freq)
-{
- struct cpufreq_freqs freqs;
-
- freqs.old = clk_get_rate(clk);
- freqs.cpu = 0;
- freqs.new = freq;
-
- if (freqs.old > 24000 && freqs.new == 24000) {
- /* turn pll off */
- __raw_writel(CLKCTRL_PLL_PWD_BIT, CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_PLL0CTRL0_CLR);
- __raw_writel(CLKCTRL_PLL_BYPASS, CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_CLKSEQ);
- } else if (freqs.old == 24000 && freqs.new > 24000)
- __raw_writel(clkseq_setting, CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_CLKSEQ);
-
- return 0;
+ if ((clk_get_usecount(usb_clk0) == 0)
+ && (clk_get_usecount(usb_clk1) == 0))
+ return 1;
+ else
+ return 0;
}
int timing_ctrl_rams(int ss)
diff --git a/arch/arm/mach-mx28/clock.c b/arch/arm/mach-mx28/clock.c
index 8e7adea7c09d..ae6f49d4ae41 100644
--- a/arch/arm/mach-mx28/clock.c
+++ b/arch/arm/mach-mx28/clock.c
@@ -22,6 +22,7 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/iram_alloc.h>
#include <linux/platform_device.h>
#include <mach/clock.h>
@@ -47,6 +48,41 @@ static unsigned long xtal_clk_rate[3] = { 24000000, 24000000, 32000 };
static unsigned long enet_mii_phy_rate;
+static inline int clk_is_busy(struct clk *clk)
+{
+ return __raw_readl(clk->busy_reg) & (1 << clk->busy_bits);
+}
+
+static bool mx28_enable_h_autoslow(bool enable)
+{
+ bool currently_enabled;
+
+ if (__raw_readl(CLKCTRL_BASE_ADDR+HW_CLKCTRL_HBUS) &
+ BM_CLKCTRL_HBUS_ASM_ENABLE)
+ currently_enabled = true;
+ else
+ currently_enabled = false;
+
+ if (enable)
+ __raw_writel(BM_CLKCTRL_HBUS_ASM_ENABLE,
+ CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_SET);
+ else
+ __raw_writel(BM_CLKCTRL_HBUS_ASM_ENABLE,
+ CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR);
+ return currently_enabled;
+}
+
+
+static void mx28_set_hbus_autoslow_flags(u16 mask)
+{
+ u32 reg;
+
+ reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
+ reg &= 0xFFFF;
+ reg |= mask << 16;
+ __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
+}
+
static int mx28_raw_enable(struct clk *clk)
{
unsigned int reg;
@@ -460,6 +496,7 @@ static unsigned long cpu_round_rate(struct clk *clk, unsigned long rate)
return rate;
}
+static struct clk h_clk;
static int cpu_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long root_rate =
@@ -469,7 +506,7 @@ static int cpu_set_rate(struct clk *clk, unsigned long rate)
u32 c = clkctrl_cpu;
u32 clkctrl_frac = 1;
u32 val;
- u32 reg_val;
+ u32 reg_val, hclk_reg;
if (rate < 24000)
return -EINVAL;
@@ -500,7 +537,31 @@ static int cpu_set_rate(struct clk *clk, unsigned long rate)
if ((abs(d) > 100) || (clkctrl_frac < 18) ||
(clkctrl_frac > 35))
return -EINVAL;
- }
+ }
+
+ /* Set safe hbus clock divider. A divider of 3 ensure that
+ * the Vddd voltage required for the cpuclk is sufficiently
+ * high for the hbus clock.
+ */
+ hclk_reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
+ if ((hclk_reg & BP_CLKCTRL_HBUS_DIV) != 3) {
+ hclk_reg &= ~(BM_CLKCTRL_HBUS_DIV);
+ hclk_reg |= BF_CLKCTRL_HBUS_DIV(3);
+
+ /* change hclk divider to safe value for any ref_cpu
+ * value.
+ */
+ __raw_writel(hclk_reg, CLKCTRL_BASE_ADDR +
+ HW_CLKCTRL_HBUS);
+ }
+
+ for (i = 10000; i; i--)
+ if (!clk_is_busy(&h_clk))
+ break;
+ if (!i) {
+ printk(KERN_ERR "couldn't set up HCLK divisor\n");
+ return -ETIMEDOUT;
+ }
/* Set Frac div */
val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC0);
@@ -510,6 +571,7 @@ static int cpu_set_rate(struct clk *clk, unsigned long rate)
/* Do not gate */
__raw_writel(BM_CLKCTRL_FRAC0_CLKGATECPU, CLKCTRL_BASE_ADDR +
HW_CLKCTRL_FRAC0_CLR);
+
/* write clkctrl_cpu */
reg_val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU);
reg_val &= ~0x3F;
@@ -824,8 +886,14 @@ static int emi_set_rate(struct clk *clk, unsigned long rate)
{
int i;
struct mxs_emi_scaling_data emi;
+ unsigned long iram_phy;
void (*f) (struct mxs_emi_scaling_data *, unsigned int *);
- f = (void *)MX28_OCRAM_BASE;
+ f = iram_alloc((unsigned int)mxs_ram_freq_scale_end -
+ (unsigned int)mxs_ram_freq_scale, &iram_phy);
+ if (NULL == f) {
+ pr_err("%s Not enough iram\n", __func__);
+ return -ENOMEM;
+ }
memcpy(f, mxs_ram_freq_scale,
(unsigned int)mxs_ram_freq_scale_end -
(unsigned int)mxs_ram_freq_scale);
@@ -852,6 +920,9 @@ static int emi_set_rate(struct clk *clk, unsigned long rate)
f(&emi, get_current_emidata());
local_fiq_enable();
local_irq_enable();
+ iram_free(iram_phy,
+ (unsigned int)mxs_ram_freq_scale_end -
+ (unsigned int)mxs_ram_freq_scale);
for (i = 10000; i; i--)
if (!clk_is_busy(clk))
@@ -1681,6 +1752,8 @@ void mx28_enet_clk_hook(void)
reg &= ~BM_CLKCTRL_ENET_SLEEP;
reg |= BM_CLKCTRL_ENET_CLK_OUT_EN;
+ /* select clock for 1588 module */
+ reg |= BM_CLKCTRL_ENET_1588_40MHZ;
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_ENET);
}
@@ -1695,4 +1768,7 @@ void __init mx28_clock_init(void)
clk_enable(&cpu_clk);
clk_enable(&emi_clk);
+
+ clk_en_public_h_asm_ctrl(mx28_enable_h_autoslow,
+ mx28_set_hbus_autoslow_flags);
}
diff --git a/arch/arm/mach-mx28/device.c b/arch/arm/mach-mx28/device.c
index 8e1d27fb1213..35e8f14a5568 100644
--- a/arch/arm/mach-mx28/device.c
+++ b/arch/arm/mach-mx28/device.c
@@ -27,13 +27,16 @@
#include <linux/platform_device.h>
#include <linux/mmc/host.h>
#include <linux/phy.h>
+#include <linux/etherdevice.h>
#include <linux/fec.h>
+#include <linux/gpmi-nfc.h>
#include <asm/mach/map.h>
#include <mach/hardware.h>
#include <mach/regs-timrot.h>
#include <mach/regs-lradc.h>
+#include <mach/regs-ocotp.h>
#include <mach/device.h>
#include <mach/dma.h>
#include <mach/lradc.h>
@@ -43,6 +46,7 @@
#include "regs-digctl.h"
#include "device.h"
+#include "mx28evk.h"
#include "mx28_pins.h"
#if defined(CONFIG_SERIAL_MXS_DUART) || \
@@ -328,76 +332,93 @@ static void __init mx28_init_i2c(void)
}
#endif
-
-#if defined(CONFIG_MTD_NAND_GPMI1)
+#if defined(CONFIG_MTD_NAND_GPMI_NFC)
extern int enable_gpmi;
-static int gpmi_pinmux_handler(void)
+static int gpmi_nfc_platform_init(unsigned int max_chip_count)
{
return !enable_gpmi;
}
-static const char *gpmi_partition_source_types[] = { "cmdlinepart", 0 };
+static void gpmi_nfc_platform_exit(unsigned int max_chip_count)
+{
+}
-static struct gpmi_platform_data gpmi_platform_data = {
- .io_uA = 70000,
+static const char *gpmi_nfc_partition_source_types[] = { "cmdlinepart", 0 };
+
+static struct gpmi_nfc_platform_data gpmi_nfc_platform_data = {
+ .nfc_version = 1,
+ .boot_rom_version = 1,
+ .clock_name = "gpmi",
+ .platform_init = gpmi_nfc_platform_init,
+ .platform_exit = gpmi_nfc_platform_exit,
.min_prop_delay_in_ns = 5,
.max_prop_delay_in_ns = 9,
- .pinmux_handler = gpmi_pinmux_handler,
+ .max_chip_count = 2,
.boot_area_size_in_bytes = 20 * SZ_1M,
+ .partition_source_types = gpmi_nfc_partition_source_types,
.partitions = 0,
.partition_count = 0,
- .partition_source_types = gpmi_partition_source_types,
};
-static struct resource gpmi_resources[] = {
+static struct resource gpmi_nfc_resources[] = {
{
+ .name = GPMI_NFC_GPMI_REGS_ADDR_RES_NAME,
.flags = IORESOURCE_MEM,
.start = GPMI_PHYS_ADDR,
.end = GPMI_PHYS_ADDR + SZ_8K - 1,
},
{
+ .name = GPMI_NFC_GPMI_INTERRUPT_RES_NAME,
.flags = IORESOURCE_IRQ,
- .start = IRQ_GPMI_DMA,
- .end = IRQ_GPMI_DMA,
- },
- {
- .flags = IORESOURCE_DMA,
- .start = MXS_DMA_CHANNEL_AHB_APBH_GPMI0,
- .end = MXS_DMA_CHANNEL_AHB_APBH_GPMI7,
- },
+ .start = IRQ_GPMI,
+ .end = IRQ_GPMI,
+ },
{
+ .name = GPMI_NFC_BCH_REGS_ADDR_RES_NAME,
.flags = IORESOURCE_MEM,
.start = BCH_PHYS_ADDR,
.end = BCH_PHYS_ADDR + SZ_8K - 1,
},
{
+ .name = GPMI_NFC_BCH_INTERRUPT_RES_NAME,
.flags = IORESOURCE_IRQ,
.start = IRQ_BCH,
.end = IRQ_BCH,
},
+ {
+ .name = GPMI_NFC_DMA_CHANNELS_RES_NAME,
+ .flags = IORESOURCE_DMA,
+ .start = MXS_DMA_CHANNEL_AHB_APBH_GPMI0,
+ .end = MXS_DMA_CHANNEL_AHB_APBH_GPMI7,
+ },
+ {
+ .name = GPMI_NFC_DMA_INTERRUPT_RES_NAME,
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_GPMI_DMA,
+ .end = IRQ_GPMI_DMA,
+ },
};
-static void __init mx28_init_gpmi(void)
+static void __init mx28_init_gpmi_nfc(void)
{
struct platform_device *pdev;
- pdev = mxs_get_device("gpmi", 0);
+ pdev = mxs_get_device(GPMI_NFC_DRIVER_NAME, 0);
if (pdev == NULL || IS_ERR(pdev))
return;
- pdev->dev.platform_data = &gpmi_platform_data;
- pdev->resource = gpmi_resources;
- pdev->num_resources = ARRAY_SIZE(gpmi_resources);
+ pdev->dev.platform_data = &gpmi_nfc_platform_data;
+ pdev->resource = gpmi_nfc_resources;
+ pdev->num_resources = ARRAY_SIZE(gpmi_nfc_resources);
mxs_add_device(pdev, 1);
}
#else
-static void mx28_init_gpmi(void)
+static void mx28_init_gpmi_nfc(void)
{
}
#endif
-
#if defined(CONFIG_MMC_MXS) || defined(CONFIG_MMC_MXS_MODULE)
#if defined(CONFIG_MACH_MX28EVK)
#define MMC0_POWER MXS_PIN_TO_GPIO(PINID_PWM3)
@@ -535,9 +556,10 @@ static struct mxs_mmc_platform_data mmc0_data = {
.get_wp = mxs_mmc_get_wp_ssp0,
.cmd_pullup = mxs_mmc_cmd_pullup_ssp0,
.setclock = mxs_mmc_setclock_ssp0,
- .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA
+ | MMC_CAP_DATA_DDR,
.min_clk = 400000,
- .max_clk = 52000000,
+ .max_clk = 48000000,
.read_uA = 50000,
.write_uA = 70000,
.clock_mmc = "ssp.0",
@@ -573,9 +595,10 @@ static struct mxs_mmc_platform_data mmc1_data = {
.get_wp = mxs_mmc_get_wp_ssp1,
.cmd_pullup = mxs_mmc_cmd_pullup_ssp1,
.setclock = mxs_mmc_setclock_ssp1,
- .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA
+ | MMC_CAP_DATA_DDR,
.min_clk = 400000,
- .max_clk = 52000000,
+ .max_clk = 48000000,
.read_uA = 50000,
.write_uA = 70000,
.clock_mmc = "ssp.1",
@@ -697,22 +720,25 @@ static void __init mx28_init_rtc(void)
#endif
#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)
-static struct resource fec_resources[] = {
+static struct resource fec0_resource[] = {
{
.start = ENET_PHYS_ADDR,
- .end = ENET_PHYS_ADDR + 0xffff,
+ .end = ENET_PHYS_ADDR + 0x3fff,
.flags = IORESOURCE_MEM
},
{
- .start = IRQ_ENET_SWI,
- .end = IRQ_ENET_SWI,
- .flags = IORESOURCE_IRQ
- },
- {
.start = IRQ_ENET_MAC0,
.end = IRQ_ENET_MAC0,
.flags = IORESOURCE_IRQ
},
+};
+
+static struct resource fec1_resource[] = {
+ {
+ .start = ENET_PHYS_ADDR + 0x4000,
+ .end = ENET_PHYS_ADDR + 0x7fff,
+ .flags = IORESOURCE_MEM
+ },
{
.start = IRQ_ENET_MAC1,
.end = IRQ_ENET_MAC1,
@@ -721,7 +747,12 @@ static struct resource fec_resources[] = {
};
extern int mx28evk_enet_gpio_init(void);
-static struct fec_platform_data fec_pdata = {
+static struct fec_platform_data fec_pdata0 = {
+ .phy = PHY_INTERFACE_MODE_RMII,
+ .init = mx28evk_enet_gpio_init,
+};
+
+static struct fec_platform_data fec_pdata1 = {
.phy = PHY_INTERFACE_MODE_RMII,
.init = mx28evk_enet_gpio_init,
};
@@ -729,22 +760,133 @@ static struct fec_platform_data fec_pdata = {
static void __init mx28_init_fec(void)
{
struct platform_device *pdev;
+ struct mxs_dev_lookup *lookup;
+ struct fec_platform_data *pfec;
+ int i;
+ u32 val;
+
+ __raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN,
+ IO_ADDRESS(OCOTP_PHYS_ADDR) + HW_OCOTP_CTRL_SET);
+
+ while (BM_OCOTP_CTRL_BUSY &
+ __raw_readl(IO_ADDRESS(OCOTP_PHYS_ADDR) + HW_OCOTP_CTRL))
+ udelay(10);
+
+ lookup = mxs_get_devices("mxs-fec");
+ if (lookup == NULL || IS_ERR(lookup))
+ return;
+
+ for (i = 0; i < lookup->size; i++) {
+ pdev = lookup->pdev + i;
+ val = __raw_readl(IO_ADDRESS(OCOTP_PHYS_ADDR) +
+ HW_OCOTP_CUSTn(pdev->id));
+ switch (pdev->id) {
+ case 0:
+ pdev->resource = fec0_resource;
+ pdev->num_resources = ARRAY_SIZE(fec0_resource);
+ pdev->dev.platform_data = &fec_pdata0;
+ break;
+ case 1:
+ pdev->resource = fec1_resource;
+ pdev->num_resources = ARRAY_SIZE(fec1_resource);
+ pdev->dev.platform_data = &fec_pdata1;
+ break;
+ default:
+ return;
+ }
+
+ pfec = (struct fec_platform_data *)pdev->dev.platform_data;
+ pfec->mac[0] = 0x00;
+ pfec->mac[1] = 0x04;
+ pfec->mac[2] = (val >> 24) & 0xFF;
+ pfec->mac[3] = (val >> 16) & 0xFF;
+ pfec->mac[4] = (val >> 8) & 0xFF;
+ pfec->mac[5] = (val >> 0) & 0xFF;
+
+ mxs_add_device(pdev, 2);
+ }
+}
+#else
+static void __init mx28_init_fec(void)
+{
+ ;
+}
+#endif
+
+#if defined(CONFIG_FEC_L2SWITCH)
+static struct resource l2switch_resources[] = {
+ {
+ .start = ENET_PHYS_ADDR,
+ .end = ENET_PHYS_ADDR + 0x17FFC,
+ .flags = IORESOURCE_MEM
+ },
+ {
+ .start = IRQ_ENET_SWI,
+ .end = IRQ_ENET_SWI,
+ .flags = IORESOURCE_IRQ
+ },
+};
+
+/* Define the fixed address of the L2 Switch hardware. */
+static unsigned int switch_platform_hw[2] = {
+ (0x800F8000),
+ (0x800FC000),
+};
+
+static struct fec_platform_data fec_enet = {
+ .phy = PHY_INTERFACE_MODE_RMII,
+ .init = mx28evk_enet_gpio_init,
+};
+
+static struct switch_platform_data l2switch_data = {
+ .id = 0,
+ .fec_enet = &fec_enet,
+ .hash_table = 0,
+ .switch_hw = switch_platform_hw,
+};
+
+static void __init mx28_init_l2switch(void)
+{
+ struct platform_device *pdev;
+ struct switch_platform_data *pswitch;
+ struct fec_platform_data *pfec;
+ u32 val;
- pdev = mxs_get_device("mxs-fec", 0);
+ __raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN,
+ IO_ADDRESS(OCOTP_PHYS_ADDR) + HW_OCOTP_CTRL_SET);
+
+ while (BM_OCOTP_CTRL_BUSY &
+ __raw_readl(IO_ADDRESS(OCOTP_PHYS_ADDR) + HW_OCOTP_CTRL))
+ udelay(10);
+
+ pdev = mxs_get_device("mxs-l2switch", 0);
if (pdev == NULL || IS_ERR(pdev))
return;
- pdev->resource = fec_resources;
- pdev->num_resources = ARRAY_SIZE(fec_resources);
- pdev->dev.platform_data = &fec_pdata;
+ val = __raw_readl(IO_ADDRESS(OCOTP_PHYS_ADDR) +
+ HW_OCOTP_CUSTn(pdev->id));
+ pdev->resource = l2switch_resources;
+ pdev->num_resources = ARRAY_SIZE(l2switch_resources);
+ pdev->dev.platform_data = &l2switch_data;
+
+ pswitch = (struct switch_platform_data *)pdev->dev.platform_data;
+ pfec = pswitch->fec_enet;
+ pfec->mac[0] = 0x00;
+ pfec->mac[1] = 0x04;
+ pfec->mac[2] = (val >> 24) & 0xFF;
+ pfec->mac[3] = (val >> 16) & 0xFF;
+ pfec->mac[4] = (val >> 8) & 0xFF;
+ pfec->mac[5] = (val >> 0) & 0xFF;
+
mxs_add_device(pdev, 2);
}
#else
-static void __init mx28_init_fec(void)
+static void __init mx28_init_l2switch(void)
{
;
}
#endif
+
#ifdef CONFIG_MXS_LRADC
struct mxs_lradc_plat_data mx28_lradc_data = {
.vddio_voltage = BV_LRADC_CTRL4_LRADC6SELECT__CHANNEL10,
@@ -1211,6 +1353,156 @@ static inline mx28_init_spdif(void)
}
#endif
+#if defined(CONFIG_MXS_PERSISTENT)
+static const struct mxs_persistent_bit_config
+mx28_persistent_bit_config[] = {
+ { .reg = 0, .start = 0, .width = 1,
+ .name = "CLOCKSOURCE" },
+ { .reg = 0, .start = 1, .width = 1,
+ .name = "ALARM_WAKE_EN" },
+ { .reg = 0, .start = 2, .width = 1,
+ .name = "ALARM_EN" },
+ { .reg = 0, .start = 3, .width = 1,
+ .name = "CLK_SECS" },
+ { .reg = 0, .start = 4, .width = 1,
+ .name = "XTAL24MHZ_PWRUP" },
+ { .reg = 0, .start = 5, .width = 1,
+ .name = "XTAL32MHZ_PWRUP" },
+ { .reg = 0, .start = 6, .width = 1,
+ .name = "XTAL32_FREQ" },
+ { .reg = 0, .start = 7, .width = 1,
+ .name = "ALARM_WAKE" },
+ { .reg = 0, .start = 8, .width = 5,
+ .name = "MSEC_RES" },
+ { .reg = 0, .start = 13, .width = 1,
+ .name = "DISABLE_XTALOK" },
+ { .reg = 0, .start = 14, .width = 2,
+ .name = "LOWERBIAS" },
+ { .reg = 0, .start = 16, .width = 1,
+ .name = "DISABLE_PSWITCH" },
+ { .reg = 0, .start = 17, .width = 1,
+ .name = "AUTO_RESTART" },
+ { .reg = 0, .start = 18, .width = 1,
+ .name = "ENABLE_LRADC_PWRUP" },
+ { .reg = 0, .start = 20, .width = 1,
+ .name = "THERMAL_RESET" },
+ { .reg = 0, .start = 21, .width = 1,
+ .name = "EXTERNAL_RESET" },
+ { .reg = 0, .start = 28, .width = 4,
+ .name = "ADJ_POSLIMITBUCK" },
+ { .reg = 1, .start = 0, .width = 1,
+ .name = "FORCE_RECOVERY" },
+ { .reg = 1, .start = 1, .width = 1,
+ .name = "ROM_REDUNDANT_BOOT" },
+ { .reg = 1, .start = 2, .width = 1,
+ .name = "NAND_SDK_BLOCK_REWRITE" },
+ { .reg = 1, .start = 3, .width = 1,
+ .name = "SD_SPEED_ENABLE" },
+ { .reg = 1, .start = 4, .width = 1,
+ .name = "SD_INIT_SEQ_1_DISABLE" },
+ { .reg = 1, .start = 5, .width = 1,
+ .name = "SD_CMD0_DISABLE" },
+ { .reg = 1, .start = 6, .width = 1,
+ .name = "SD_INIT_SEQ_2_ENABLE" },
+ { .reg = 1, .start = 7, .width = 1,
+ .name = "OTG_ATL_ROLE_BIT" },
+ { .reg = 1, .start = 8, .width = 1,
+ .name = "OTG_HNP_BIT" },
+ { .reg = 1, .start = 9, .width = 1,
+ .name = "USB_LOW_POWER_MODE" },
+ { .reg = 1, .start = 10, .width = 1,
+ .name = "SKIP_CHECKDISK" },
+ { .reg = 1, .start = 11, .width = 1,
+ .name = "USB_BOOT_PLAYER_MODE" },
+ { .reg = 1, .start = 12, .width = 1,
+ .name = "ENUMERATE_500MA_TWICE" },
+ { .reg = 1, .start = 13, .width = 19,
+ .name = "SPARE_GENERAL" },
+
+ { .reg = 2, .start = 0, .width = 32,
+ .name = "SPARE_2" },
+ { .reg = 3, .start = 0, .width = 32,
+ .name = "SPARE_3" },
+ { .reg = 4, .start = 0, .width = 32,
+ .name = "SPARE_4" },
+ { .reg = 5, .start = 0, .width = 32,
+ .name = "SPARE_5" },
+};
+
+static struct mxs_platform_persistent_data mx28_persistent_data = {
+ .bit_config_tab = mx28_persistent_bit_config,
+ .bit_config_cnt = ARRAY_SIZE(mx28_persistent_bit_config),
+};
+
+static struct resource mx28_persistent_res[] = {
+ {
+ .flags = IORESOURCE_MEM,
+ .start = RTC_PHYS_ADDR,
+ .end = RTC_PHYS_ADDR + 0x2000 - 1,
+ },
+};
+
+static void mx28_init_persistent(void)
+{
+ struct platform_device *pdev;
+ pdev = mxs_get_device("mxs-persistent", 0);
+ if (pdev == NULL || IS_ERR(pdev))
+ return;
+ pdev->dev.platform_data = &mx28_persistent_data;
+ pdev->resource = mx28_persistent_res,
+ pdev->num_resources = ARRAY_SIZE(mx28_persistent_res),
+ mxs_add_device(pdev, 3);
+}
+#else
+static void mx28_init_persistent()
+{
+}
+#endif
+
+#if defined(CONFIG_FSL_OTP)
+/* Building up eight registers's names of a bank */
+#define BANK(a, b, c, d, e, f, g, h) \
+ {\
+ ("HW_OCOTP_"#a), ("HW_OCOTP_"#b), ("HW_OCOTP_"#c), ("HW_OCOTP_"#d), \
+ ("HW_OCOTP_"#e), ("HW_OCOTP_"#f), ("HW_OCOTP_"#g), ("HW_OCOTP_"#h) \
+ }
+
+#define BANKS (5)
+#define BANK_ITEMS (8)
+static const char *bank_reg_desc[BANKS][BANK_ITEMS] = {
+ BANK(CUST0, CUST1, CUST2, CUST3, CRYPTO0, CRYPTO1, CRYPTO2, CRYPTO3),
+ BANK(HWCAP0, HWCAP1, HWCAP2, HWCAP3, HWCAP4, HWCAP5, SWCAP, CUSTCAP),
+ BANK(LOCK, OPS0, OPS1, OPS2, OPS3, UN0, UN1, UN2),
+ BANK(ROM0, ROM1, ROM2, ROM3, ROM4, ROM5, ROM6, ROM7),
+ BANK(SRK0, SRK1, SRK2, SRK3, SRK4, SRK5, SRK6, SRK7),
+};
+
+static struct fsl_otp_data otp_data = {
+ .fuse_name = (char **)bank_reg_desc,
+ .regulator_name = "vddio",
+ .fuse_num = BANKS * BANK_ITEMS,
+};
+#undef BANK
+#undef BANKS
+#undef BANK_ITEMS
+
+static void __init mx28_init_otp(void)
+{
+ struct platform_device *pdev;
+ pdev = mxs_get_device("ocotp", 0);
+ if (pdev == NULL || IS_ERR(pdev))
+ return;
+ pdev->dev.platform_data = &otp_data;
+ pdev->resource = NULL;
+ pdev->num_resources = 0;
+ mxs_add_device(pdev, 3);
+}
+#else
+static void mx28_init_otp(void)
+{
+}
+#endif
+
int __init mx28_device_init(void)
{
mx28_init_dma();
@@ -1220,10 +1512,11 @@ int __init mx28_device_init(void)
mx28_init_lradc();
mx28_init_auart();
mx28_init_mmc();
- mx28_init_gpmi();
+ mx28_init_gpmi_nfc();
mx28_init_wdt();
mx28_init_rtc();
mx28_init_fec();
+ mx28_init_l2switch();
mx28_init_flexcan();
mx28_init_kbd();
mx28_init_ts();
@@ -1233,7 +1526,8 @@ int __init mx28_device_init(void)
mx28_init_pxp();
mx28_init_dcp();
mx28_init_battery();
-
+ mx28_init_persistent();
+ mx28_init_otp();
return 0;
}
diff --git a/arch/arm/mach-mx28/emi_settings.c b/arch/arm/mach-mx28/emi_settings.c
index 7dd62b9dd65a..56df6ad0c0d4 100644
--- a/arch/arm/mach-mx28/emi_settings.c
+++ b/arch/arm/mach-mx28/emi_settings.c
@@ -27,7 +27,6 @@
#include <linux/platform_device.h>
#include <linux/mmc/host.h>
#include <linux/phy.h>
-#include <linux/fec.h>
#include <asm/mach/map.h>
diff --git a/arch/arm/mach-mx28/include/mach/mx28.h b/arch/arm/mach-mx28/include/mach/mx28.h
index f74b8941fad2..097253266709 100644
--- a/arch/arm/mach-mx28/include/mach/mx28.h
+++ b/arch/arm/mach-mx28/include/mach/mx28.h
@@ -226,12 +226,17 @@
#define MX28_SOC_IO_ADDRESS(x) \
((x) - MX28_SOC_IO_PHYS_BASE + MX28_SOC_IO_VIRT_BASE)
+#ifdef __ASSEMBLER__
+#define IO_ADDRESS(x) \
+ MX28_SOC_IO_ADDRESS(x)
+#else
#define IO_ADDRESS(x) \
(void __force __iomem *) \
(((x) >= (unsigned long)MX28_SOC_IO_PHYS_BASE) && \
((x) < (unsigned long)MX28_SOC_IO_PHYS_BASE + \
MX28_SOC_IO_AREA_SIZE) ? \
MX28_SOC_IO_ADDRESS(x) : 0xDEADBEEF)
+#endif
#ifdef CONFIG_MXS_EARLY_CONSOLE
#define MXS_DEBUG_CONSOLE_PHYS DUART_PHYS_ADDR
diff --git a/arch/arm/mach-mx28/mx28evk.c b/arch/arm/mach-mx28/mx28evk.c
index 650d16a4fb0a..37beb27f7065 100644
--- a/arch/arm/mach-mx28/mx28evk.c
+++ b/arch/arm/mach-mx28/mx28evk.c
@@ -39,7 +39,7 @@ static struct i2c_board_info __initdata mxs_i2c_device[] = {
{ I2C_BOARD_INFO("sgtl5000-i2c", 0x14), .flags = I2C_M_TEN }
};
-static void i2c_device_init(void)
+static void __init i2c_device_init(void)
{
i2c_register_board_info(0, mxs_i2c_device, ARRAY_SIZE(mxs_i2c_device));
}
@@ -104,7 +104,12 @@ static void __init mx28evk_init_machine(void)
{
mx28_pinctrl_init();
/* Init iram allocate */
+#ifdef CONFIG_VECTORS_PHY_ADDR
+ /* reserve the first page for irq vector table*/
+ iram_init(MX28_OCRAM_PHBASE + PAGE_SIZE, MX28_OCRAM_SIZE - PAGE_SIZE);
+#else
iram_init(MX28_OCRAM_PHBASE, MX28_OCRAM_SIZE);
+#endif
mx28_gpio_init();
mx28evk_pins_init();
diff --git a/arch/arm/mach-mx28/mx28evk.h b/arch/arm/mach-mx28/mx28evk.h
index c141749cc183..d973c0f7ef19 100644
--- a/arch/arm/mach-mx28/mx28evk.h
+++ b/arch/arm/mach-mx28/mx28evk.h
@@ -20,4 +20,9 @@
#define __ASM_ARM_MACH_MX28EVK_H
extern void __init mx28evk_pins_init(void);
+extern int mx28evk_enet_gpio_init(void);
+void mx28evk_enet_io_lowerpower_enter(void);
+void mx28evk_enet_io_lowerpower_exit(void);
+
+
#endif /* __ASM_ARM_MACH_MX28EVK_H */
diff --git a/arch/arm/mach-mx28/mx28evk_pins.c b/arch/arm/mach-mx28/mx28evk_pins.c
index 8bb253607658..7d5b64328324 100644
--- a/arch/arm/mach-mx28/mx28evk_pins.c
+++ b/arch/arm/mach-mx28/mx28evk_pins.c
@@ -21,6 +21,7 @@
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/gpio.h>
+#include <linux/delay.h>
#include <mach/pinctrl.h>
@@ -530,15 +531,106 @@ static struct pin_desc mx28evk_fixed_pins[] = {
.name = "SSP0_SCK",
.id = PINID_SSP0_SCK,
.fun = PIN_FUN1,
- .strength = PAD_8MA,
+ .strength = PAD_12MA,
.voltage = PAD_3_3V,
.pullup = 0,
- .drive = 1,
+ .drive = 2,
.pull = 0,
},
#endif
+#if defined(CONFIG_LEDS_MXS) || defined(CONFIG_LEDS_MXS_MODULE)
+ {
+ .name = "LEDS_PWM0",
+ .id = PINID_AUART1_RX,
+ .fun = PIN_FUN3,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "LEDS_PWM1",
+ .id = PINID_AUART1_TX,
+ .fun = PIN_FUN3,
+ .strength = PAD_8MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+#endif
+#if defined(CONFIG_SND_MXS_SOC_DAI) || defined(CONFIG_SND_MXS_SOC_DAI_MODULE)
+ /* Configurations of SAIF0 port pins */
+ {
+ .name = "SAIF0_MCLK",
+ .id = PINID_SAIF0_MCLK,
+ .fun = PIN_FUN1,
+ .strength = PAD_12MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SAIF0_LRCLK",
+ .id = PINID_SAIF0_LRCLK,
+ .fun = PIN_FUN1,
+ .strength = PAD_12MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SAIF0_BITCLK",
+ .id = PINID_SAIF0_BITCLK,
+ .fun = PIN_FUN1,
+ .strength = PAD_12MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SAIF0_SDATA0",
+ .id = PINID_SAIF0_SDATA0,
+ .fun = PIN_FUN1,
+ .strength = PAD_12MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+ {
+ .name = "SAIF1_SDATA0",
+ .id = PINID_SAIF1_SDATA0,
+ .fun = PIN_FUN1,
+ .strength = PAD_12MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+#endif
+#if defined(CONFIG_SND_SOC_MXS_SPDIF) || \
+ defined(CONFIG_SND_SOC_MXS_SPDIF_MODULE)
+ {
+ .name = "SPDIF",
+ .id = PINID_SPDIF,
+ .fun = PIN_FUN1,
+ .strength = PAD_12MA,
+ .voltage = PAD_3_3V,
+ .pullup = 1,
+ .drive = 1,
+ .pull = 1,
+ },
+#endif
+};
-#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)
+#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)\
+ || defined(CONFIG_FEC_L2SWITCH)
+static struct pin_desc mx28evk_eth_pins[] = {
{
.name = "ENET0_MDC",
.id = PINID_ENET0_MDC,
@@ -620,106 +712,77 @@ static struct pin_desc mx28evk_fixed_pins[] = {
.drive = 1,
},
{
- .name = "ENET_CLK",
- .id = PINID_ENET_CLK,
- .fun = PIN_FUN1,
+ .name = "ENET1_RX_EN",
+ .id = PINID_ENET0_CRS,
+ .fun = PIN_FUN2,
.strength = PAD_8MA,
.pull = 1,
.pullup = 1,
.voltage = PAD_3_3V,
- .drive = 1,
- },
-#endif
-#if defined(CONFIG_LEDS_MXS) || defined(CONFIG_LEDS_MXS_MODULE)
- {
- .name = "LEDS_PWM0",
- .id = PINID_AUART1_RX,
- .fun = PIN_FUN3,
- .strength = PAD_8MA,
- .voltage = PAD_3_3V,
- .pullup = 1,
- .drive = 1,
- .pull = 1,
+ .drive = 1,
},
{
- .name = "LEDS_PWM1",
- .id = PINID_AUART1_TX,
- .fun = PIN_FUN3,
- .strength = PAD_8MA,
- .voltage = PAD_3_3V,
- .pullup = 1,
- .drive = 1,
- .pull = 1,
+ .name = "ENET1_RXD0",
+ .id = PINID_ENET0_RXD2,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .pull = 1,
+ .pullup = 1,
+ .voltage = PAD_3_3V,
+ .drive = 1,
},
-#endif
-#if defined(CONFIG_SND_MXS_SOC_DAI) || defined(CONFIG_SND_MXS_SOC_DAI_MODULE)
- /* Configurations of SAIF0 port pins */
{
- .name = "SAIF0_MCLK",
- .id = PINID_SAIF0_MCLK,
- .fun = PIN_FUN1,
- .strength = PAD_12MA,
- .voltage = PAD_3_3V,
- .pullup = 1,
- .drive = 1,
- .pull = 1,
+ .name = "ENET1_RXD1",
+ .id = PINID_ENET0_RXD3,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .pull = 1,
+ .pullup = 1,
+ .voltage = PAD_3_3V,
+ .drive = 1,
},
{
- .name = "SAIF0_LRCLK",
- .id = PINID_SAIF0_LRCLK,
- .fun = PIN_FUN1,
- .strength = PAD_12MA,
- .voltage = PAD_3_3V,
- .pullup = 1,
- .drive = 1,
- .pull = 1,
+ .name = "ENET1_TX_EN",
+ .id = PINID_ENET0_COL,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .pull = 1,
+ .pullup = 1,
+ .voltage = PAD_3_3V,
+ .drive = 1,
},
{
- .name = "SAIF0_BITCLK",
- .id = PINID_SAIF0_BITCLK,
- .fun = PIN_FUN1,
- .strength = PAD_12MA,
- .voltage = PAD_3_3V,
- .pullup = 1,
- .drive = 1,
- .pull = 1,
+ .name = "ENET1_TXD0",
+ .id = PINID_ENET0_TXD2,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .pull = 1,
+ .pullup = 1,
+ .voltage = PAD_3_3V,
+ .drive = 1,
},
{
- .name = "SAIF0_SDATA0",
- .id = PINID_SAIF0_SDATA0,
- .fun = PIN_FUN1,
- .strength = PAD_12MA,
- .voltage = PAD_3_3V,
- .pullup = 1,
- .drive = 1,
- .pull = 1,
+ .name = "ENET1_TXD1",
+ .id = PINID_ENET0_TXD3,
+ .fun = PIN_FUN2,
+ .strength = PAD_8MA,
+ .pull = 1,
+ .pullup = 1,
+ .voltage = PAD_3_3V,
+ .drive = 1,
},
{
- .name = "SAIF1_SDATA0",
- .id = PINID_SAIF1_SDATA0,
- .fun = PIN_FUN1,
- .strength = PAD_12MA,
- .voltage = PAD_3_3V,
- .pullup = 1,
- .drive = 1,
- .pull = 1,
+ .name = "ENET_CLK",
+ .id = PINID_ENET_CLK,
+ .fun = PIN_FUN1,
+ .strength = PAD_8MA,
+ .pull = 1,
+ .pullup = 1,
+ .voltage = PAD_3_3V,
+ .drive = 1,
},
-#endif
-#if defined(CONFIG_SND_SOC_MXS_SPDIF) || \
- defined(CONFIG_SND_SOC_MXS_SPDIF_MODULE)
- {
- .name = "SPDIF",
- .id = PINID_SPDIF,
- .fun = PIN_FUN1,
- .strength = PAD_12MA,
- .voltage = PAD_3_3V,
- .pullup = 1,
- .drive = 1,
- .pull = 1,
- },
-#endif
};
-
+#endif
static int __initdata enable_ssp1 = { 0 };
static int __init ssp1_setup(char *__unused)
@@ -835,16 +898,16 @@ static struct pin_desc mx28evk_ssp1_pins[] = {
.name = "SSP1_SCK",
.id = PINID_GPMI_WRN,
.fun = PIN_FUN2,
- .strength = PAD_8MA,
+ .strength = PAD_12MA,
.voltage = PAD_3_3V,
.pullup = 0,
- .drive = 1,
+ .drive = 2,
.pull = 0,
},
};
-int __initdata enable_gpmi = { 0 };
+int enable_gpmi = { 0 };
static int __init gpmi_setup(char *__unused)
{
enable_gpmi = 1;
@@ -1009,7 +1072,8 @@ static struct pin_desc mx28evk_gpmi_pins[] = {
},
};
-#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)
+#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)\
+ || defined(CONFIG_FEC_L2SWITCH)
int mx28evk_enet_gpio_init(void)
{
/* pwr */
@@ -1019,15 +1083,54 @@ int mx28evk_enet_gpio_init(void)
/* reset phy */
gpio_request(MXS_PIN_TO_GPIO(PINID_ENET0_RX_CLK), "PHY_RESET");
gpio_direction_output(MXS_PIN_TO_GPIO(PINID_ENET0_RX_CLK), 0);
+ mdelay(10);
gpio_direction_output(MXS_PIN_TO_GPIO(PINID_ENET0_RX_CLK), 1);
return 0;
}
+
+void mx28evk_enet_io_lowerpower_enter(void)
+{
+ int i;
+ gpio_direction_output(MXS_PIN_TO_GPIO(PINID_SSP1_DATA3), 1);
+ gpio_direction_output(MXS_PIN_TO_GPIO(PINID_ENET0_RX_CLK), 0);
+ gpio_request(MXS_PIN_TO_GPIO(PINID_ENET0_TX_CLK), "ETH_INT");
+ gpio_direction_output(MXS_PIN_TO_GPIO(PINID_ENET0_TX_CLK), 0);
+
+ for (i = 0; i < ARRAY_SIZE(mx28evk_eth_pins); i++) {
+ mxs_release_pin(mx28evk_eth_pins[i].id,
+ mx28evk_eth_pins[i].name);
+ gpio_request(MXS_PIN_TO_GPIO(mx28evk_eth_pins[i].id),
+ mx28evk_eth_pins[i].name);
+ gpio_direction_output(
+ MXS_PIN_TO_GPIO(mx28evk_eth_pins[i].id), 0);
+ }
+
+}
+
+void mx28evk_enet_io_lowerpower_exit(void)
+{
+ int i;
+ gpio_direction_output(MXS_PIN_TO_GPIO(PINID_SSP1_DATA3), 0);
+ gpio_direction_output(MXS_PIN_TO_GPIO(PINID_ENET0_RX_CLK), 1);
+ gpio_free(MXS_PIN_TO_GPIO(PINID_ENET0_TX_CLK));
+ for (i = 0; i < ARRAY_SIZE(mx28evk_eth_pins); i++) {
+ gpio_free(MXS_PIN_TO_GPIO(mx28evk_eth_pins[i].id));
+ mxs_request_pin(mx28evk_eth_pins[i].id,
+ mx28evk_eth_pins[i].fun,
+ mx28evk_eth_pins[i].name);
+ }
+}
+
#else
int mx28evk_enet_gpio_init(void)
{
return 0;
}
+void mx28evk_enet_io_lowerpower_enter(void)
+{}
+void mx28evk_enet_io_lowerpower_exit(void)
+{}
#endif
void __init mx28evk_init_pin_group(struct pin_desc *pins, unsigned count)
@@ -1071,5 +1174,9 @@ void __init mx28evk_pins_init(void)
mx28evk_init_pin_group(mx28evk_gpmi_pins,
ARRAY_SIZE(mx28evk_gpmi_pins));
}
-
+#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)\
+ || defined(CONFIG_FEC_L2SWITCH)
+ mx28evk_init_pin_group(mx28evk_eth_pins,
+ ARRAY_SIZE(mx28evk_eth_pins));
+#endif
}
diff --git a/arch/arm/mach-mx28/pm.c b/arch/arm/mach-mx28/pm.c
index c26a495f59e2..4ac13bc3248c 100644
--- a/arch/arm/mach-mx28/pm.c
+++ b/arch/arm/mach-mx28/pm.c
@@ -36,12 +36,13 @@
#include <mach/dma.h>
#include <mach/regs-rtc.h>
#include "regs-clkctrl.h"
-#include "regs-pinctrl.h"
#include <mach/regs-power.h>
#include <mach/regs-pwm.h>
#include <mach/regs-rtc.h>
#include <mach/../../regs-icoll.h>
#include "regs-dram.h"
+#include "mx28_pins.h"
+#include "mx28evk.h"
#include "sleep.h"
@@ -79,7 +80,8 @@ static inline void do_standby(void)
u32 reg_clkctrl_clkseq, reg_clkctrl_xtal;
unsigned long iram_phy_addr;
void *iram_virtual_addr;
-
+ int wakeupirq;
+ mx28evk_enet_io_lowerpower_enter();
/*
* 1) switch clock domains from PLL to 24MHz
* 2) lower voltage (TODO)
@@ -110,7 +112,8 @@ static inline void do_standby(void)
cpu_parent = clk_get_parent(cpu_clk);
hbus_rate = clk_get_rate(hbus_clk);
clk_set_parent(cpu_clk, osc_clk);
- }
+ } else
+ pr_err("fail to get cpu clk\n");
local_fiq_disable();
@@ -122,15 +125,18 @@ static inline void do_standby(void)
reg_clkctrl_xtal = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL);
+
/* do suspend */
mx28_cpu_standby_ptr = iram_virtual_addr;
mx28_cpu_standby_ptr();
+ wakeupirq = __raw_readl(IO_ADDRESS(ICOLL_PHYS_ADDR) + HW_ICOLL_STAT);
+
+ pr_info("wakeup irq = %d\n", wakeupirq);
__raw_writel(reg_clkctrl_clkseq, REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ);
__raw_writel(reg_clkctrl_xtal, REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL);
-
saved_sleep_state = 0; /* waking from standby */
__raw_writel(BM_POWER_CTRL_PSWITCH_IRQ,
REGS_POWER_BASE + HW_POWER_CTRL_CLR);
@@ -149,6 +155,7 @@ static inline void do_standby(void)
clk_put(cpu_clk);
iram_free(iram_phy_addr, MAX_POWEROFF_CODE_SIZE);
+ mx28evk_enet_io_lowerpower_exit();
}
static noinline void do_mem(void)
@@ -255,38 +262,52 @@ static struct mx28_pswitch_state pswitch_state = {
.dev_running = 0,
};
-static irqreturn_t pswitch_interrupt(int irq, void *dev)
+#define PSWITCH_POWER_DOWN_DELAY 30
+static struct delayed_work pswitch_work;
+static void pswitch_check_work(struct work_struct *work)
{
int pin_value, i;
-
- /* check if irq by pswitch */
- if (!(__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) &
- BM_POWER_CTRL_PSWITCH_IRQ))
- return IRQ_HANDLED;
- for (i = 0; i < 3000; i++) {
+ for (i = 0; i < PSWITCH_POWER_DOWN_DELAY; i++) {
pin_value = __raw_readl(REGS_POWER_BASE + HW_POWER_STS) &
BF_POWER_STS_PSWITCH(0x1);
if (pin_value == 0)
break;
- mdelay(1);
+ msleep(100);
}
- if (i < 3000) {
+ if (i < PSWITCH_POWER_DOWN_DELAY) {
pr_info("pswitch goto suspend\n");
complete(&suspend_request);
} else {
pr_info("release pswitch to power down\n");
- for (i = 0; i < 5000; i++) {
+ for (i = 0; i < 500; i++) {
pin_value = __raw_readl(REGS_POWER_BASE + HW_POWER_STS)
& BF_POWER_STS_PSWITCH(0x1);
if (pin_value == 0)
break;
- mdelay(1);
+ msleep(10);
}
pr_info("pswitch power down\n");
mx28_pm_power_off();
}
__raw_writel(BM_POWER_CTRL_PSWITCH_IRQ,
REGS_POWER_BASE + HW_POWER_CTRL_CLR);
+ __raw_writel(BM_POWER_CTRL_ENIRQ_PSWITCH,
+ REGS_POWER_BASE + HW_POWER_CTRL_SET);
+ __raw_writel(BM_POWER_CTRL_PSWITCH_IRQ,
+ REGS_POWER_BASE + HW_POWER_CTRL_CLR);
+}
+
+
+static irqreturn_t pswitch_interrupt(int irq, void *dev)
+{
+
+ /* check if irq by pswitch */
+ if (!(__raw_readl(REGS_POWER_BASE + HW_POWER_CTRL) &
+ BM_POWER_CTRL_PSWITCH_IRQ))
+ return IRQ_HANDLED;
+ __raw_writel(BM_POWER_CTRL_ENIRQ_PSWITCH,
+ REGS_POWER_BASE + HW_POWER_CTRL_CLR);
+ schedule_delayed_work(&pswitch_work, 1);
return IRQ_HANDLED;
}
@@ -299,6 +320,7 @@ static struct irqaction pswitch_irq = {
static void init_pswitch(void)
{
+ INIT_DELAYED_WORK(&pswitch_work, pswitch_check_work);
kthread_run(suspend_thread_fn, NULL, "pswitch");
__raw_writel(BM_POWER_CTRL_PSWITCH_IRQ,
REGS_POWER_BASE + HW_POWER_CTRL_CLR);
diff --git a/arch/arm/mach-mx28/regs-clkctrl.h b/arch/arm/mach-mx28/regs-clkctrl.h
index 161860c2fcf0..9de19275fa91 100644
--- a/arch/arm/mach-mx28/regs-clkctrl.h
+++ b/arch/arm/mach-mx28/regs-clkctrl.h
@@ -478,6 +478,7 @@
#define BM_CLKCTRL_ENET_RSRVD0 0x0000FFFF
#define BF_CLKCTRL_ENET_RSRVD0(v) \
(((v) << 0) & BM_CLKCTRL_ENET_RSRVD0)
+#define BM_CLKCTRL_ENET_1588_40MHZ 0x01880000
#define HW_CLKCTRL_HSADC (0x00000150)
diff --git a/arch/arm/mach-mx28/sleep.S b/arch/arm/mach-mx28/sleep.S
index 438f588f85d3..54e86bd4f717 100644
--- a/arch/arm/mach-mx28/sleep.S
+++ b/arch/arm/mach-mx28/sleep.S
@@ -25,6 +25,7 @@
#include <mach/hardware.h>
#include <mach/regs-power.h>
#include <mach/regs-rtc.h>
+#include "regs-pinctrl.h"
#include "regs-clkctrl.h"
#include "regs-dram.h"
#include "sleep.h"
@@ -39,11 +40,104 @@
#define HW_DRAM_CTL17_ADDR \
(MX28_SOC_IO_ADDRESS(DRAM_PHYS_ADDR) + HW_DRAM_CTL17)
+#define HW_DRAM_CTL22_ADDR \
+ (MX28_SOC_IO_ADDRESS(DRAM_PHYS_ADDR) + HW_DRAM_CTL22)
+
#define HW_RTC_PERSISTENT0_ADDR \
(MX28_SOC_IO_ADDRESS(RTC_PHYS_ADDR) + HW_RTC_PERSISTENT0)
+#define HW_CLKCTRL_EMI_ADDR \
+ (MX28_SOC_IO_ADDRESS(CLKCTRL_PHYS_ADDR) + HW_CLKCTRL_EMI)
+#define HW_CLKCTRL_PLL0CTRL0_ADDR \
+ (MX28_SOC_IO_ADDRESS(CLKCTRL_PHYS_ADDR) + HW_CLKCTRL_PLL0CTRL0)
+#define HW_POWER_VDDIOCTRL_ADDR \
+ (MX28_SOC_IO_ADDRESS(POWER_PHYS_ADDR) + HW_POWER_VDDIOCTRL)
+#define HW_POWER_VDDDCTRL_ADDR \
+ (MX28_SOC_IO_ADDRESS(POWER_PHYS_ADDR) + HW_POWER_VDDDCTRL)
+#define HW_POWER_VDDACTRL_ADDR \
+ (MX28_SOC_IO_ADDRESS(POWER_PHYS_ADDR) + HW_POWER_VDDACTRL)
+#define HW_PINCTRL_EMI_DS_CTRL_ADDR \
+ (MX28_SOC_IO_ADDRESS(PINCTRL_PHYS_ADDR) + HW_PINCTRL_EMI_DS_CTRL)
+
+#define HW_POWER_LOOPCTRL_ADDR \
+ (MX28_SOC_IO_ADDRESS(POWER_PHYS_ADDR) + HW_POWER_LOOPCTRL)
+
+#define HW_POWER_MINPWR_ADDR \
+ (MX28_SOC_IO_ADDRESS(POWER_PHYS_ADDR) + HW_POWER_MINPWR)
#define PHYS_RAM_START 0x40000000
+#define LOWER_VDDIO 6
+#define LOWER_VDDA 9
+#define LOWER_VDDD 0x16
+
+#define VDDIOCTRL_BACKUP 0
+#define VDDACTRL_BACKUP 1
+#define VDDDCTRL_BACKUP 2
+#define POWER_LOOPCTRL_BACKUP 3
+#define POWER_MINPWR_BACKUP 4
+
+.macro PM_BITS_SET, addr, val
+ mov r0, #(\addr & 0x000000FF)
+ orr r0, r0, #(\addr & 0x0000FF00)
+ orr r0, r0, #(\addr & 0x00FF0000)
+ orr r0, r0, #(\addr & 0xFF000000)
+ ldr r1, [r0]
+ orr r1, r1, #(\val)
+ str r1, [r0]
+.endm
+
+.macro PM_BITS_CLR, addr, val
+ mov r0, #(\addr & 0x000000FF)
+ orr r0, r0, #(\addr & 0x0000FF00)
+ orr r0, r0, #(\addr & 0x00FF0000)
+ orr r0, r0, #(\addr & 0xFF000000)
+ ldr r1, [r0]
+ bic r1, r1, #(\val)
+ str r1, [r0]
+.endm
+
+.macro PM_BACKUP_REG, addr, num
+ mov r0, #(\addr & 0x000000FF)
+ orr r0, r0, #(\addr & 0x0000FF00)
+ orr r0, r0, #(\addr & 0x00FF0000)
+ orr r0, r0, #(\addr & 0xFF000000)
+ ldr r1, [r0]
+ str r1, __mx28_temp_stack + \num * 4
+.endm
+
+.macro PM_WRITE_REG_MASK, addr, bitmask, val
+ mov r0, #(\addr & 0x000000FF)
+ orr r0, r0, #(\addr & 0x0000FF00)
+ orr r0, r0, #(\addr & 0x00FF0000)
+ orr r0, r0, #(\addr & 0xFF000000)
+ ldr r1, [r0]
+ bic r1, r1, #(\bitmask)
+ orr r1, r1, #(\val)
+ str r1, [r0]
+.endm
+
+.macro PM_SET_AND_BACKUP_REG, addr, bitmask, val, num
+ mov r0, #(\addr & 0x000000FF)
+ orr r0, r0, #(\addr & 0x0000FF00)
+ orr r0, r0, #(\addr & 0x00FF0000)
+ orr r0, r0, #(\addr & 0xFF000000)
+ ldr r1, [r0]
+ str r1, __mx28_temp_stack + \num * 4
+ bic r1, r1, #(\bitmask)
+ orr r1, r1, #(\val)
+ str r1, [r0]
+.endm
+
+.macro PM_SET_RESTORE_REG, addr, num
+ mov r0, #(\addr & 0x000000FF)
+ orr r0, r0, #(\addr & 0x0000FF00)
+ orr r0, r0, #(\addr & 0x00FF0000)
+ orr r0, r0, #(\addr & 0xFF000000)
+ ldr r1, __mx28_temp_stack + \num * 4
+ str r1, [r0]
+.endm
+
+
.global cpu_arm926_switch_mm
.text
@@ -59,7 +153,6 @@ ENTRY(mx28_cpu_standby)
ldr r1, __mx28_flush_cache_addr
mov lr, pc
mov pc, r1
-
@ put DRAM into self refresh
mov r0, #(HW_DRAM_CTL17_ADDR & 0x000000FF)
orr r0, r0, #(HW_DRAM_CTL17_ADDR & 0x0000FF00)
@@ -69,6 +162,67 @@ ENTRY(mx28_cpu_standby)
orr r1, r1, #(BM_DRAM_CTL17_SREFRESH)
str r1, [r0]
@ wait for it to actually happen
+ mov r0, #24 << 5
+11: sub r0, r0, #1
+ cmp r0, #0
+ bne 11b
+
+ @ gate clk
+ mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF)
+ orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00)
+ orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000)
+ orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000)
+ ldr r1, [r0]
+ orr r1, r1, #(BM_CLKCTRL_EMI_CLKGATE)
+ str r1, [r0]
+
+// PM_SET_AND_BACKUP_REG HW_PINCTRL_EMI_DS_CTRL_ADDR,\
+// BM_PINCTRL_EMI_DS_CTRL_DDR_MODE,\
+// BF_PINCTRL_EMI_DS_CTRL_DDR_MODE(0x1), 4
+
+ // vddio
+ PM_SET_AND_BACKUP_REG HW_POWER_VDDIOCTRL_ADDR,\
+ BM_POWER_VDDIOCTRL_TRG, LOWER_VDDIO, VDDIOCTRL_BACKUP
+ mov r0, #24 << 10
+1: sub r0, r0, #1
+ cmp r0, #0
+ bne 1b
+
+ PM_SET_AND_BACKUP_REG HW_POWER_VDDACTRL_ADDR,\
+ BM_POWER_VDDACTRL_TRG, LOWER_VDDA, VDDACTRL_BACKUP
+ mov r0, #24 << 10
+2: sub r0, r0, #1
+ cmp r0, #0
+ bne 2b
+
+ PM_SET_AND_BACKUP_REG HW_POWER_VDDDCTRL_ADDR,\
+ BM_POWER_VDDDCTRL_TRG, LOWER_VDDD, VDDDCTRL_BACKUP
+ mov r0, #24 << 10
+3: sub r0, r0, #1
+ cmp r0, #0
+ bne 3b
+
+ PM_BACKUP_REG HW_POWER_LOOPCTRL_ADDR, POWER_LOOPCTRL_BACKUP
+ PM_BACKUP_REG HW_POWER_MINPWR_ADDR, POWER_MINPWR_BACKUP
+
+// PM_BITS_CLR HW_POWER_LOOPCTRL_ADDR, BM_POWER_LOOPCTRL_EN_RCSCALE
+// PM_WRITE_REG_MASK HW_POWER_LOOPCTRL_ADDR, BM_POWER_LOOPCTRL_DC_R,\
+// (2<<BP_POWER_LOOPCTRL_DC_R)
+
+ // half fets
+ PM_BITS_SET HW_POWER_MINPWR_ADDR, BM_POWER_MINPWR_HALF_FETS
+
+ PM_BITS_CLR HW_POWER_LOOPCTRL_ADDR, BM_POWER_LOOPCTRL_CM_HYST_THRESH
+ PM_BITS_CLR HW_POWER_LOOPCTRL_ADDR, BM_POWER_LOOPCTRL_EN_CM_HYST
+ PM_BITS_CLR HW_POWER_LOOPCTRL_ADDR, BM_POWER_LOOPCTRL_EN_DF_HYST
+
+ // enable PFM
+ PM_BITS_SET HW_POWER_LOOPCTRL_ADDR, BM_POWER_LOOPCTRL_HYST_SIGN
+ PM_BITS_SET HW_POWER_MINPWR_ADDR, BM_POWER_MINPWR_EN_DC_PFM
+
+
+ //Gated PLL0
+ PM_BITS_CLR HW_CLKCTRL_PLL0CTRL0_ADDR, BM_CLKCTRL_PLL0CTRL0_POWER
@ do enter standby
mov r0, #(HW_CLKCTRL_CPU_ADDR & 0x000000FF)
@@ -89,6 +243,39 @@ ENTRY(mx28_cpu_standby)
nop
nop
+ PM_BITS_SET HW_CLKCTRL_PLL0CTRL0_ADDR, BM_CLKCTRL_PLL0CTRL0_POWER
+
+ PM_SET_RESTORE_REG HW_POWER_MINPWR_ADDR, POWER_MINPWR_BACKUP
+
+ PM_SET_RESTORE_REG HW_POWER_LOOPCTRL_ADDR, POWER_LOOPCTRL_BACKUP
+
+ // vddio
+ PM_SET_RESTORE_REG HW_POWER_VDDIOCTRL_ADDR, VDDIOCTRL_BACKUP
+ mov r0, #24 << 10
+10: sub r0, r0, #1
+ cmp r0, #0
+ bne 10b
+ PM_SET_RESTORE_REG HW_POWER_VDDACTRL_ADDR, VDDACTRL_BACKUP
+ mov r0, #24 << 10
+20: sub r0, r0, #1
+ cmp r0, #0
+ bne 20b
+ PM_SET_RESTORE_REG HW_POWER_VDDDCTRL_ADDR, VDDDCTRL_BACKUP
+ mov r0, #24 << 10
+30: sub r0, r0, #1
+ cmp r0, #0
+ bne 30b
+
+ @ ungate clk
+ mov r0, #(HW_CLKCTRL_EMI_ADDR & 0x000000FF)
+ orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x0000FF00)
+ orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0x00FF0000)
+ orr r0, r0, #(HW_CLKCTRL_EMI_ADDR & 0xFF000000)
+ ldr r1, [r0]
+ bic r1, r1, #(BM_CLKCTRL_EMI_CLKGATE)
+ str r1, [r0]
+
+// PM_SET_RESTORE_REG HW_PINCTRL_EMI_DS_CTRL_ADDR, 4
@ restore normal DRAM mode
mov r0, #(HW_DRAM_CTL17_ADDR & 0x000000FF)
orr r0, r0, #(HW_DRAM_CTL17_ADDR & 0x0000FF00)
@@ -98,6 +285,10 @@ ENTRY(mx28_cpu_standby)
bic r1, r1, #BM_DRAM_CTL17_SREFRESH
str r1, [r0]
@ wait for it to actually happen
+ mov r0, #24 << 5
+12: sub r0, r0, #1
+ cmp r0, #0
+ bne 12b
nop
nop
@@ -108,7 +299,7 @@ ENTRY(mx28_cpu_standby)
.space 0x100
__mx28_temp_stack:
- .word 0
+ .space 128
#ifdef CONFIG_STMP378X_RAM_FREQ_SCALING
#include "emi.inc"
diff --git a/arch/arm/mach-mx28/usb_dr.c b/arch/arm/mach-mx28/usb_dr.c
index 13344ef0e26f..50a2f8b381af 100644
--- a/arch/arm/mach-mx28/usb_dr.c
+++ b/arch/arm/mach-mx28/usb_dr.c
@@ -63,7 +63,7 @@ static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = {
};
/*
- * resources
+ * OTG resources
*/
static struct resource otg_resources[] = {
[0] = {
@@ -78,6 +78,22 @@ static struct resource otg_resources[] = {
},
};
+/*
+ * UDC resources (same as OTG resource)
+ */
+static struct resource udc_resources[] = {
+ [0] = {
+ .start = (u32)USBCTRL0_PHYS_ADDR,
+ .end = (u32)(USBCTRL0_PHYS_ADDR + 0x1ff),
+ .flags = IORESOURCE_MEM,
+ },
+
+ [1] = {
+ .start = IRQ_USB0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static u64 dr_udc_dmamask = ~(u32) 0;
static void dr_udc_release(struct device *dev)
{
@@ -111,8 +127,8 @@ static struct platform_device __maybe_unused dr_otg_device = {
.dma_mask = &dr_otg_dmamask,
.coherent_dma_mask = 0xffffffff,
},
- .resource = otg_resources,
- .num_resources = ARRAY_SIZE(otg_resources),
+ .resource = udc_resources,
+ .num_resources = ARRAY_SIZE(udc_resources),
};
@@ -156,5 +172,5 @@ void fsl_phy_set_power(struct fsl_xcvr_ops *this,
#ifdef CONFIG_MXS_VBUS_CURRENT_DRAW
fs_initcall(usb_dr_init);
#else
- module_init(usb_dr_init);
+ subsys_initcall(usb_dr_init);
#endif
diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c
index 2861ecf81235..c7d9560f0850 100644
--- a/arch/arm/mach-mx3/devices.c
+++ b/arch/arm/mach-mx3/devices.c
@@ -891,6 +891,22 @@ static inline void mxc_init_iim(void)
}
#endif
+static struct platform_device mxc_v4l2_device = {
+ .name = "mxc_v4l2_capture",
+ .id = 0,
+};
+
+static struct platform_device mxc_v4l2out_device = {
+ .name = "mxc_v4l2_output",
+ .id = 0,
+};
+
+static inline void mxc_init_v4l2()
+{
+ platform_device_register(&mxc_v4l2_device);
+ platform_device_register(&mxc_v4l2out_device);
+}
+
int __init mxc_init_devices(void)
{
mxc_init_wdt();
@@ -910,6 +926,7 @@ int __init mxc_init_devices(void)
mxc_init_vpu();
mxc_init_rnga();
mxc_init_iim();
+ mxc_init_v4l2();
return 0;
}
diff --git a/arch/arm/mach-mx3/mx31ads.c b/arch/arm/mach-mx3/mx31ads.c
index 92c16045e391..b5d63339b498 100644
--- a/arch/arm/mach-mx3/mx31ads.c
+++ b/arch/arm/mach-mx3/mx31ads.c
@@ -1241,16 +1241,16 @@ static struct fsl_ata_platform_data ata_data = {
};
static struct resource pata_fsl_resources[] = {
- [0] = { /* I/O */
- .start = ATA_BASE_ADDR + 0x00,
- .end = ATA_BASE_ADDR + 0xD8,
- .flags = IORESOURCE_MEM,
- },
- [2] = { /* IRQ */
- .start = MXC_INT_ATA,
- .end = MXC_INT_ATA,
- .flags = IORESOURCE_IRQ,
- },
+ {
+ .start = ATA_BASE_ADDR,
+ .end = ATA_BASE_ADDR + 0x000000D8,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_ATA,
+ .end = MXC_INT_ATA,
+ .flags = IORESOURCE_IRQ,
+ },
};
static struct platform_device pata_fsl_device = {
diff --git a/arch/arm/mach-mx3/mx3_3stack.c b/arch/arm/mach-mx3/mx3_3stack.c
index 4a97f688a75d..516890f020a4 100644
--- a/arch/arm/mach-mx3/mx3_3stack.c
+++ b/arch/arm/mach-mx3/mx3_3stack.c
@@ -92,13 +92,17 @@ static struct resource mxc_kpp_resources[] = {
.start = MXC_INT_KPP,
.end = MXC_INT_KPP,
.flags = IORESOURCE_IRQ,
- }
+ },
+ [1] = {
+ .start = KPP_BASE_ADDR,
+ .end = KPP_BASE_ADDR + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
};
static struct keypad_data keypad_plat_data = {
.rowmax = 3,
.colmax = 4,
- .irq = MXC_INT_KPP,
.learning = 0,
.delay = 2,
.matrix = keymapping,
@@ -168,6 +172,20 @@ static struct platform_device mxc_nand_mtd_device = {
},
};
+static struct resource mxc_nand_resources[] = {
+ {
+ .flags = IORESOURCE_MEM,
+ .name = "NFC_AXI_BASE",
+ .start = NFC_BASE_ADDR,
+ .end = NFC_BASE_ADDR + SZ_4K - 1,
+ },
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = MXC_INT_NANDFC,
+ .end = MXC_INT_NANDFC,
+ },
+};
+
static struct platform_device mxc_nandv2_mtd_device = {
.name = "mxc_nandv2_flash",
.id = 0,
@@ -175,6 +193,8 @@ static struct platform_device mxc_nandv2_mtd_device = {
.release = mxc_nop_release,
.platform_data = &mxc_nand_data,
},
+ .resource = mxc_nand_resources,
+ .num_resources = ARRAY_SIZE(mxc_nand_resources),
};
static void mxc_init_nand_mtd(void)
@@ -835,16 +855,16 @@ static struct fsl_ata_platform_data ata_data = {
};
static struct resource pata_fsl_resources[] = {
- [0] = { /* I/O */
- .start = ATA_BASE_ADDR + 0x00,
- .end = ATA_BASE_ADDR + 0xD8,
- .flags = IORESOURCE_MEM,
- },
- [2] = { /* IRQ */
- .start = MXC_INT_ATA,
- .end = MXC_INT_ATA,
- .flags = IORESOURCE_IRQ,
- },
+ {
+ .start = ATA_BASE_ADDR,
+ .end = ATA_BASE_ADDR + 0x000000D8,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_ATA,
+ .end = MXC_INT_ATA,
+ .flags = IORESOURCE_IRQ,
+ },
};
static struct platform_device pata_fsl_device = {
diff --git a/arch/arm/mach-mx3/usb_dr.c b/arch/arm/mach-mx3/usb_dr.c
index 7331463173e9..d84fea7f1a80 100644
--- a/arch/arm/mach-mx3/usb_dr.c
+++ b/arch/arm/mach-mx3/usb_dr.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -59,7 +59,7 @@ static struct fsl_usb2_platform_data __maybe_unused dr_1504_config = {
/*
- * resources
+ * OTG resources
*/
static struct resource otg_resources[] = {
[0] = {
@@ -73,6 +73,20 @@ static struct resource otg_resources[] = {
},
};
+/*
+ * UDC resources (same as OTG resource)
+ */
+static struct resource udc_resources[] = {
+ [0] = {
+ .start = (u32)(USB_OTGREGS_BASE),
+ .end = (u32)(USB_OTGREGS_BASE + 0x1ff),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = MXC_INT_USB3,
+ .flags = IORESOURCE_IRQ,
+ },
+};
static u64 dr_udc_dmamask = ~(u32) 0;
static void dr_udc_release(struct device *dev)
@@ -96,8 +110,8 @@ static struct platform_device __maybe_unused dr_udc_device = {
.dma_mask = &dr_udc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
- .resource = otg_resources,
- .num_resources = ARRAY_SIZE(otg_resources),
+ .resource = udc_resources,
+ .num_resources = ARRAY_SIZE(udc_resources),
};
static struct platform_device __maybe_unused dr_otg_device = {
diff --git a/arch/arm/mach-mx35/devices.c b/arch/arm/mach-mx35/devices.c
index 7687d0e0b09d..02c971659bd4 100644
--- a/arch/arm/mach-mx35/devices.c
+++ b/arch/arm/mach-mx35/devices.c
@@ -585,11 +585,58 @@ static inline void mxc_init_spdif(void)
platform_device_register(&mxc_alsa_spdif_device);
}
+#if defined(CONFIG_SND_MXC_SOC_ESAI) || defined(CONFIG_SND_MXC_SOC_ESAI_MODULE)
+
+static struct mxc_esai_platform_data esai_data = {
+ .activate_esai_ports = gpio_activate_esai_ports,
+ .deactivate_esai_ports = gpio_deactivate_esai_ports,
+};
+
+static struct resource esai_resources[] = {
+ {
+ .start = ESAI_BASE_ADDR,
+ .end = ESAI_BASE_ADDR + 0x100,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_ESAI,
+ .end = MXC_INT_ESAI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device mxc_esai_device = {
+ .name = "mxc_esai",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(esai_resources),
+ .resource = esai_resources,
+ .dev = {
+ .release = mxc_nop_release,
+ .platform_data = &esai_data,
+ },
+};
+
+static void mxc_init_esai(void)
+{
+ platform_device_register(&mxc_esai_device);
+}
+#else
+static void mxc_init_esai(void)
+{
+
+}
+#endif
+
+static struct mxc_audio_platform_data mxc_surround_audio_data = {
+ .ext_ram = 1,
+};
+
static struct platform_device mxc_alsa_surround_device = {
.name = "imx-3stack-wm8580",
.id = 0,
.dev = {
.release = mxc_nop_release,
+ .platform_data = &mxc_surround_audio_data,
},
};
@@ -855,6 +902,22 @@ static inline void mxc_init_ssi(void)
}
#endif /* CONFIG_SND_MXC_SOC_SSI */
+static struct platform_device mxc_v4l2_device = {
+ .name = "mxc_v4l2_capture",
+ .id = 0,
+};
+
+static struct platform_device mxc_v4l2out_device = {
+ .name = "mxc_v4l2_output",
+ .id = 0,
+};
+
+static inline void mxc_init_v4l2()
+{
+ platform_device_register(&mxc_v4l2_device);
+ platform_device_register(&mxc_v4l2out_device);
+}
+
int __init mxc_init_devices(void)
{
mxc_init_wdt();
@@ -873,6 +936,8 @@ int __init mxc_init_devices(void)
mxc_init_iim();
mxc_init_gpu();
mxc_init_ssi();
+ mxc_init_esai();
+ mxc_init_v4l2();
return 0;
}
diff --git a/arch/arm/mach-mx35/mx35_3stack.c b/arch/arm/mach-mx35/mx35_3stack.c
index c6752fe10c5c..868cf12ca2e6 100644
--- a/arch/arm/mach-mx35/mx35_3stack.c
+++ b/arch/arm/mach-mx35/mx35_3stack.c
@@ -171,6 +171,20 @@ static struct mtd_partition mxc_nand_partitions[] = {
.size = MTDPART_SIZ_FULL},
};
+static struct resource mxc_nand_resources[] = {
+ {
+ .flags = IORESOURCE_MEM,
+ .name = "NFC_AXI_BASE",
+ .start = NFC_BASE_ADDR,
+ .end = NFC_BASE_ADDR + SZ_8K - 1,
+ },
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = MXC_INT_NANDFC,
+ .end = MXC_INT_NANDFC,
+ },
+};
+
static struct flash_platform_data mxc_nand_data = {
.parts = mxc_nand_partitions,
.nr_parts = ARRAY_SIZE(mxc_nand_partitions),
@@ -184,6 +198,8 @@ static struct platform_device mxc_nand_mtd_device = {
.release = mxc_nop_release,
.platform_data = &mxc_nand_data,
},
+ .resource = mxc_nand_resources,
+ .num_resources = ARRAY_SIZE(mxc_nand_resources),
};
static void mxc_init_nand_mtd(void)
@@ -402,7 +418,7 @@ static struct mxc_fm_platform_data si4702_data = {
static void adv7180_pwdn(int pwdn)
{
- pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_1, 1, pwdn);
+ pmic_gpio_set_bit_val(MCU_GPIO_REG_GPIO_CONTROL_1, 1, ~pwdn);
}
static void adv7180_reset(void)
@@ -589,6 +605,13 @@ static struct mxc_mmc_platform_data mmc1_data = {
#endif
.min_clk = 150000,
.max_clk = 52000000,
+ /* Do not disable the eSDHC clk on MX35 3DS board,
+ * since SYSTEM can't boot up after the reset key
+ * is pressed when the SD/MMC boot mode is used.
+ * The root cause is that the ROM code don't ensure
+ * the SD/MMC clk is running when boot system.
+ * */
+ .clk_always_on = 1,
.card_inserted_state = 0,
.status = sdhc_get_card_det_status,
.wp_status = sdhc_write_protect,
@@ -635,6 +658,7 @@ static struct mxc_mmc_platform_data mmc2_data = {
.caps = MMC_CAP_4_BIT_DATA,
.min_clk = 150000,
.max_clk = 50000000,
+ .clk_always_on = 1,
.card_inserted_state = 0,
.status = sdhc_get_card_det_status,
.wp_status = sdhc_write_protect,
@@ -765,16 +789,16 @@ static struct fsl_ata_platform_data ata_data = {
};
static struct resource pata_fsl_resources[] = {
- [0] = { /* I/O */
- .start = ATA_BASE_ADDR,
- .end = ATA_BASE_ADDR + 0x000000C8,
- .flags = IORESOURCE_MEM,
- },
- [2] = { /* IRQ */
- .start = MXC_INT_ATA,
- .end = MXC_INT_ATA,
- .flags = IORESOURCE_IRQ,
- },
+ {
+ .start = ATA_BASE_ADDR,
+ .end = ATA_BASE_ADDR + 0x000000C8,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_ATA,
+ .end = MXC_INT_ATA,
+ .flags = IORESOURCE_IRQ,
+ },
};
static struct platform_device pata_fsl_device = {
diff --git a/arch/arm/mach-mx35/usb_dr.c b/arch/arm/mach-mx35/usb_dr.c
index 18f76b90907a..4ebb27c5342b 100644
--- a/arch/arm/mach-mx35/usb_dr.c
+++ b/arch/arm/mach-mx35/usb_dr.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -37,7 +37,7 @@ static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = {
/*
- * resources
+ * OTG resources
*/
static struct resource otg_resources[] = {
[0] = {
@@ -51,6 +51,20 @@ static struct resource otg_resources[] = {
},
};
+/*
+ * UDC resources (same as OTG resource)
+ */
+static struct resource udc_resources[] = {
+ [0] = {
+ .start = (u32)(USB_OTGREGS_BASE),
+ .end = (u32)(USB_OTGREGS_BASE + 0x1ff),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = MXC_INT_USBOTG,
+ .flags = IORESOURCE_IRQ,
+ },
+};
static u64 dr_udc_dmamask = ~(u32) 0;
static void dr_udc_release(struct device *dev)
@@ -74,8 +88,8 @@ static struct platform_device __maybe_unused dr_udc_device = {
.dma_mask = &dr_udc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
- .resource = otg_resources,
- .num_resources = ARRAY_SIZE(otg_resources),
+ .resource = udc_resources,
+ .num_resources = ARRAY_SIZE(udc_resources),
};
static struct platform_device __maybe_unused dr_otg_device = {
diff --git a/arch/arm/mach-mx37/cpu.c b/arch/arm/mach-mx37/cpu.c
index 3729ac11ca80..3832473f781e 100644
--- a/arch/arm/mach-mx37/cpu.c
+++ b/arch/arm/mach-mx37/cpu.c
@@ -25,6 +25,7 @@
#include <asm/hardware/cache-l2x0.h>
void __iomem *gpc_base;
+void __iomem *ccm_base;
/*!
* CPU initialization. It is called by fixup_mxc_board()
@@ -73,6 +74,7 @@ static int __init post_cpu_init(void)
iram_init(IRAM_BASE_ADDR, iram_size);
gpc_base = ioremap(GPC_BASE_ADDR, SZ_4K);
+ ccm_base = ioremap(CCM_BASE_ADDR, SZ_4K);
/* Set ALP bits to 000. Set ALP_EN bit in Arm Memory Controller reg. */
reg = __raw_readl(MXC_ARM1176_BASE + 0x1C);
diff --git a/arch/arm/mach-mx37/crm_regs.h b/arch/arm/mach-mx37/crm_regs.h
index a03bc4e103f5..bfb9bff13d46 100644
--- a/arch/arm/mach-mx37/crm_regs.h
+++ b/arch/arm/mach-mx37/crm_regs.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -10,6 +10,7 @@
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
+
#ifndef __ARCH_ARM_MACH_MX37_CRM_REGS_H__
#define __ARCH_ARM_MACH_MX37_CRM_REGS_H__
@@ -501,6 +502,11 @@
#define MXC_CCM_CCGR5_CG1_OFFSET 2
#define MXC_CCM_CCGR5_CG0_OFFSET 0
+/* CCM Register Offsets. */
+#define MXC_CCM_CDCR_OFFSET 0x6C
+#define MXC_CCM_CACRR_OFFSET 0x10
+#define MXC_CCM_CDHIPR_OFFSET 0x68
+
#define MXC_ARM1176_BASE IO_ADDRESS(ARM1176_BASE_ADDR)
#define MXC_GPC_BASE IO_ADDRESS(GPC_BASE_ADDR)
#define MXC_DPTC_LP_BASE IO_ADDRESS(GPC_BASE_ADDR + 0x80)
@@ -529,6 +535,11 @@
#define MXC_GPC_PGR (MXC_GPC_BASE + 0x4)
#define MXC_GPC_VCR (MXC_GPC_BASE + 0x8)
+/*GPC OFFSETS */
+#define MXC_GPC_CNTR_OFFSET 0x0
+#define MXC_GPC_PGR_OFFSET 0x4
+#define MXC_GPC_VCR_OFFSET 0x8
+
/* DVFS CORE */
#define MXC_DVFSTHRS (MXC_DVFS_CORE_BASE + 0x00)
#define MXC_DVFSCOUN (MXC_DVFS_CORE_BASE + 0x04)
@@ -548,21 +559,13 @@
#define MXC_DVFSPT2 (MXC_DVFS_CORE_BASE + 0x3C)
#define MXC_DVFSPT3 (MXC_DVFS_CORE_BASE + 0x40)
-/* DPTC GP */
-#define MXC_GP_DPTCCR (MXC_DPTC_GP_BASE + 0x00)
-#define MXC_GP_DPTCDBG (MXC_DPTC_GP_BASE + 0x04)
-#define MXC_GP_DCVR0 (MXC_DPTC_GP_BASE + 0x08)
-#define MXC_GP_DCVR1 (MXC_DPTC_GP_BASE + 0x0C)
-#define MXC_GP_DCVR2 (MXC_DPTC_GP_BASE + 0x10)
-#define MXC_GP_DCVR3 (MXC_DPTC_GP_BASE + 0x14)
-
-/* DPTC LP */
-#define MXC_LP_DPTCCR (MXC_DPTC_LP_BASE + 0x00)
-#define MXC_LP_DPTCDBG (MXC_DPTC_LP_BASE + 0x04)
-#define MXC_LP_DCVR0 (MXC_DPTC_LP_BASE + 0x08)
-#define MXC_LP_DCVR1 (MXC_DPTC_LP_BASE + 0x0C)
-#define MXC_LP_DCVR2 (MXC_DPTC_LP_BASE + 0x10)
-#define MXC_LP_DCVR3 (MXC_DPTC_LP_BASE + 0x14)
+/* DPTC register offset */
+#define MXC_DPTCCR 0x00
+#define MXC_DPTCDBG 0x04
+#define MXC_DCVR0 0x08
+#define MXC_DCVR1 0x0C
+#define MXC_DCVR2 0x10
+#define MXC_DCVR3 0x14
#define MXC_DPTCCR_DRCE3 0x00400000
#define MXC_DPTCCR_DRCE2 0x00200000
diff --git a/arch/arm/mach-mx37/devices.c b/arch/arm/mach-mx37/devices.c
index e346899cb2cf..ce1f33112396 100644
--- a/arch/arm/mach-mx37/devices.c
+++ b/arch/arm/mach-mx37/devices.c
@@ -645,8 +645,8 @@ void __init mxc_init_tve(void)
*/
static struct resource dvfs_core_resources[] = {
[0] = {
- .start = MXC_DVFS_CORE_BASE,
- .end = MXC_DVFS_CORE_BASE + 4 * SZ_16 - 1,
+ .start = DVFSCORE_BASE_ADDR,
+ .end = DVFSCORE_BASE_ADDR + 4 * SZ_16 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -661,15 +661,11 @@ struct mxc_dvfs_platform_data dvfs_core_data = {
.reg_id = "SW1",
.clk1_id = "cpu_clk",
.clk2_id = "gpc_dvfs_clk",
- .gpc_cntr_reg_addr = MXC_GPC_CNTR,
- .gpc_vcr_reg_addr = MXC_GPC_VCR,
- .ccm_cdcr_reg_addr = MXC_CCM_CDCR,
- .ccm_cacrr_reg_addr = MXC_CCM_CACRR,
- .ccm_cdhipr_reg_addr = MXC_CCM_CDHIPR,
- .dvfs_thrs_reg_addr = MXC_DVFSTHRS,
- .dvfs_coun_reg_addr = MXC_DVFSCOUN,
- .dvfs_emac_reg_addr = MXC_DVFSEMAC,
- .dvfs_cntr_reg_addr = MXC_DVFSCNTR,
+ .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET,
+ .gpc_vcr_offset = MXC_GPC_VCR_OFFSET,
+ .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET,
+ .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET,
+ .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET,
.prediv_mask = 0x3800,
.prediv_offset = 11,
.prediv_val = 1,
@@ -710,8 +706,8 @@ static inline void mxc_init_dvfs_core(void)
*/
static struct resource dptc_gp_resources[] = {
[0] = {
- .start = MXC_DPTC_GP_BASE,
- .end = MXC_DPTC_GP_BASE + 8 * SZ_16 - 1,
+ .start = DPTCGP_BASE_ADDR,
+ .end = DPTCGP_BASE_ADDR + 8 * SZ_16 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -725,8 +721,8 @@ static struct resource dptc_gp_resources[] = {
struct mxc_dptc_data dptc_gp_data = {
.reg_id = "SW1",
.clk_id = "cpu_clk",
- .dptccr_reg_addr = MXC_GP_DPTCCR,
- .dcvr0_reg_addr = MXC_GP_DCVR0,
+ .dptccr_reg_addr = MXC_DPTCCR,
+ .dcvr0_reg_addr = MXC_DCVR0,
.gpc_cntr_reg_addr = MXC_GPC_CNTR,
.dptccr = MXC_GPCCNTR_DPTC0CR,
.dptc_wp_supported = DPTC_GP_WP_SUPPORTED,
@@ -754,8 +750,8 @@ struct mxc_dptc_data dptc_gp_data = {
*/
static struct resource dptc_lp_resources[] = {
[0] = {
- .start = MXC_DPTC_LP_BASE,
- .end = MXC_DPTC_LP_BASE + 8 * SZ_16 - 1,
+ .start = DPTCLP_BASE_ADDR,
+ .end = DPTCLP_BASE_ADDR + 8 * SZ_16 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -769,8 +765,8 @@ static struct resource dptc_lp_resources[] = {
struct mxc_dptc_data dptc_lp_data = {
.reg_id = "SW2",
.clk_id = "ahb_clk",
- .dptccr_reg_addr = MXC_LP_DPTCCR,
- .dcvr0_reg_addr = MXC_LP_DCVR0,
+ .dptccr_reg_addr = MXC_DPTCCR,
+ .dcvr0_reg_addr = MXC_DCVR0,
.gpc_cntr_reg_addr = MXC_GPC_CNTR,
.dptccr = MXC_GPCCNTR_DPTC1CR,
.dptc_wp_supported = DPTC_LP_WP_SUPPORTED,
@@ -1172,6 +1168,22 @@ static inline void mxc_init_ssi(void)
}
#endif /* CONFIG_SND_MXC_SOC_SSI */
+static struct platform_device mxc_v4l2_device = {
+ .name = "mxc_v4l2_capture",
+ .id = 0,
+};
+
+static struct platform_device mxc_v4l2out_device = {
+ .name = "mxc_v4l2_output",
+ .id = 0,
+};
+
+static inline void mxc_init_v4l2()
+{
+ platform_device_register(&mxc_v4l2_device);
+ platform_device_register(&mxc_v4l2out_device);
+}
+
int __init mxc_init_devices(void)
{
mxc_init_wdt();
@@ -1193,6 +1205,7 @@ int __init mxc_init_devices(void)
mxc_init_rngc();
mxc_init_iim();
mxc_init_ssi();
+ mxc_init_v4l2();
return 0;
}
diff --git a/arch/arm/mach-mx37/mx37_3stack.c b/arch/arm/mach-mx37/mx37_3stack.c
index 2a5200031af5..26be2f49d316 100644
--- a/arch/arm/mach-mx37/mx37_3stack.c
+++ b/arch/arm/mach-mx37/mx37_3stack.c
@@ -206,6 +206,26 @@ static struct mtd_partition mxc_nand_partitions[] = {
.size = MTDPART_SIZ_FULL},
};
+static struct resource mxc_nand_resources[] = {
+ {
+ .flags = IORESOURCE_MEM,
+ .name = "NFC_AXI_BASE",
+ .start = NFC_BASE_ADDR_AXI,
+ .end = NFC_BASE_ADDR_AXI + SZ_8K - 1,
+ },
+ {
+ .flags = IORESOURCE_MEM,
+ .name = "NFC_IP_BASE",
+ .start = NFC_BASE_ADDR + 0x00,
+ .end = NFC_BASE_ADDR + 0x34 - 1,
+ },
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = MXC_INT_EMI,
+ .end = MXC_INT_EMI,
+ },
+};
+
static struct flash_platform_data mxc_nand_data = {
.parts = mxc_nand_partitions,
.nr_parts = ARRAY_SIZE(mxc_nand_partitions),
@@ -219,6 +239,9 @@ static struct platform_device mxc_nandv2_mtd_device = {
.release = mxc_nop_release,
.platform_data = &mxc_nand_data,
},
+ .resource = mxc_nand_resources,
+ .num_resources = ARRAY_SIZE(mxc_nand_resources),
+
};
static void mxc_init_nand_mtd(void)
@@ -425,6 +448,7 @@ static void mxc_init_fb(void)
printk(KERN_INFO "TV is primary display\n");
fb_data.interface_pix_fmt = IPU_PIX_FMT_YUV444;
fb_data.mode = &tv_mode;
+ fb_data.num_modes = 1;
mxc_fb_device[1].dev.platform_data = &fb_data;
(void)platform_device_register(&mxc_fb_device[1]);
(void)platform_device_register(&mxc_fb_device[0]);
@@ -525,16 +549,16 @@ static struct fsl_ata_platform_data ata_data = {
};
static struct resource pata_fsl_resources[] = {
- [0] = { /* I/O */
- .start = ATA_BASE_ADDR,
- .end = ATA_BASE_ADDR + 0x000000C8,
- .flags = IORESOURCE_MEM,
- },
- [2] = { /* IRQ */
- .start = MXC_INT_ATA,
- .end = MXC_INT_ATA,
- .flags = IORESOURCE_IRQ,
- },
+ {
+ .start = ATA_BASE_ADDR,
+ .end = ATA_BASE_ADDR + 0x000000C8,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_ATA,
+ .end = MXC_INT_ATA,
+ .flags = IORESOURCE_IRQ,
+ },
};
static struct platform_device pata_fsl_device = {
diff --git a/arch/arm/mach-mx37/usb_dr.c b/arch/arm/mach-mx37/usb_dr.c
index c8cbed1cc2d4..eb7fc463526c 100644
--- a/arch/arm/mach-mx37/usb_dr.c
+++ b/arch/arm/mach-mx37/usb_dr.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -43,7 +43,7 @@ static struct fsl_usb2_platform_data __maybe_unused dr_utmi_config = {
/*
- * resources
+ * OTG resources
*/
static struct resource otg_resources[] = {
[0] = {
@@ -57,7 +57,20 @@ static struct resource otg_resources[] = {
},
};
-
+/*
+ * UDC resources (same as OTG resource)
+ */
+static struct resource udc_resources[] = {
+ [0] = {
+ .start = (u32)(OTG_BASE_ADDR),
+ .end = (u32)(OTG_BASE_ADDR + 0x620),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = MXC_INT_USB_OTG,
+ .flags = IORESOURCE_IRQ,
+ },
+};
static u64 dr_udc_dmamask = ~(u32) 0;
static void dr_udc_release(struct device *dev)
{
@@ -75,8 +88,8 @@ static struct platform_device dr_udc_device = {
.dma_mask = &dr_udc_dmamask,
.coherent_dma_mask = 0xffffffff,
},
- .resource = otg_resources,
- .num_resources = ARRAY_SIZE(otg_resources),
+ .resource = udc_resources,
+ .num_resources = ARRAY_SIZE(udc_resources),
};
static u64 dr_otg_dmamask = ~(u32) 0;
diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig
index 5dd3e0fa0b99..7152e3c0f34f 100644
--- a/arch/arm/mach-mx5/Kconfig
+++ b/arch/arm/mach-mx5/Kconfig
@@ -2,10 +2,15 @@ if ARCH_MX5
config ARCH_MX51
bool "MX51"
+ select ARCH_MXC_IOMUX_V3
config ARCH_MX53
bool "MX53"
+config ARCH_MX50
+ bool
+ select ARCH_HAS_RNGC
+
config FORCE_MAX_ZONEORDER
int "MAX_ORDER"
default "13"
@@ -21,7 +26,8 @@ config MX5_MULTI_ARCH
bool
default y
select RUNTIME_PHYS_OFFSET
- depends on ARCH_MX51 && ARCH_MX53
+ depends on ARCH_MX51
+ depends on ARCH_MX50 || ARCH_MX53
config MACH_MX51_3DS
bool "Support MX51 3-Stack platform"
@@ -44,12 +50,31 @@ config MACH_MX53_EVK
Include support for MX53 EVK platform. This includes specific
configurations for the board and its peripherals.
+config MACH_MX50_ARM2
+ bool "Support MX50 Armadillo2 platform"
+ select ARCH_MX50
+ help
+ Include support for MX50 EVK platform. This includes specific
+ configurations for the board and its peripherals.
+
+
config MODULE_CCXMX51
bool
+config LATE_CPU_CLK_ENABLE
+ bool
+
+config MACH_MX50_RDP
+ bool "Support MX50 Reference Design Platform"
+ select ARCH_MX50
+ help
+ Include support for MX50 RDP platform. This includes specific
+ configurations for the board and its peripherals.
+
config MACH_CCWMX51JS
bool "Support for the ConnectCore Wi-i.MX51 module, on the JSK base board"
select MODULE_CCXMX51
+ select LATE_CPU_CLK_ENABLE
help
Include support for the Digi ConnectCore Wi-i.MX51 Embedded Module, on the
JumpStart Kit base board. This includes specific configurations for the
@@ -58,11 +83,64 @@ config MACH_CCWMX51JS
config MACH_CCWMX51
bool "Support for the ConnectCore Wi-i.MX51 module"
select MODULE_CCXMX51
+ select LATE_CPU_CLK_ENABLE
help
Include support for the Digi ConnectCore Wi-i.MX51 Embedded Module, on a
custom board. The machine file should be modified to include support for
the interfaces available in that board.
+config MACH_CCMX51JS
+ bool "Support for the ConnectCore i.MX51 module, on the JSK base board"
+ select MODULE_CCXMX51
+ select LATE_CPU_CLK_ENABLE
+ help
+ Include support for the Digi ConnectCore i.MX51 Embedded Module, on the
+ JumpStart Kit base board. This includes specific configurations for the
+ peripherals on that base board.
+
+config MACH_CCMX51
+ bool "Support for the ConnectCore i.MX51 module"
+ select MODULE_CCXMX51
+ select LATE_CPU_CLK_ENABLE
+ help
+ Include support for the Digi ConnectCore i.MX51 Embedded Module, on a
+ custom board. The machine file should be modified to include support for
+ the interfaces available in that board.
+
+choice
+ prompt "Select development board variant:"
+ default JSCCWMX51_V2
+
+config JSCCWMX51_V1
+ bool "ConnectCore for i.MX51 Early Availability Development Board"
+ depends on MODULE_CCXMX51
+ select CCWMX51_DISP0_RGB888 if CCWMX51_DISP0
+ help
+ Select this option if you are using the development board included in
+ the Early Availability (EA) kit. The Digi part number for this board
+ revision is 30011032-01. It is printed on the top side of the
+ development board, close to the connectors of Signal Rail 1.
+
+config JSCCWMX51_V2
+ bool "ConnectCore for i.MX51 JumpStart Kit Development Board"
+ depends on MODULE_CCXMX51
+ select CCWMX51_DISP0_RGB666 if CCWMX51_DISP0
+ help
+ Select this option if you are using the development board included in
+ Digi JumpStart Kit. The Digi part number for this board revision is
+ 30011032-03. It is printed on the top side of the development board,
+ close to the connectors of Signal Rail 1.
+
+config JSCCWMX51_CUSTOM
+ bool "Custom ConnectCore for i.MX51 Carrier Board"
+ depends on MODULE_CCXMX51
+ help
+ Select this option if you are using your own custom-designed carrier
+ board.
+
+endchoice
+
+
comment "MX5x Options:"
config MXC_SDMA_API
@@ -72,6 +150,9 @@ config MXC_SDMA_API
This selects the Freescale MXC SDMA API.
If unsure, say N.
+config MXC_NAND_SWAP_BI
+ bool
+
config ARCH_MXC_HAS_NFC_V3
bool "MXC NFC Hardware Version 3"
depends on ARCH_MX5
@@ -83,9 +164,10 @@ config ARCH_MXC_HAS_NFC_V3
config ARCH_MXC_HAS_NFC_V3_2
bool "MXC NFC Hardware Version 3.2"
depends on ARCH_MXC_HAS_NFC_V3
+ select MXC_NAND_SWAP_BI if MODULE_CCXMX51
default y
help
- This selects the Freescale MXC Nand Flash Controller Hardware Version 3.1
+ This selects the Freescale MXC Nand Flash Controller Hardware Version 3.2
If unsure, say N.
config SDMA_IRAM
@@ -100,50 +182,112 @@ menu "Serial Port Options"
config UART1_ENABLED
bool "Enable UART1"
default y
- depends on SERIAL_MXC && MACH_CCWMX51JS
+ depends on SERIAL_MXC && MODULE_CCXMX51
help
Enable the MX51 UART1 interface
+choice
+ prompt "Select the configuration for the UART lines:"
+ default UART1_2WIRE_ENABLED
+ depends on UART1_ENABLED
+
+config UART1_2WIRE_ENABLED
+ bool "Configure UART1 as 2 wire UART (RX/TX)"
+
+config UART1_CTS_RTS_ENABLED
+ bool "Configure UART1 as 4 wire UART (RX/TX/RTS/CTS)"
+
+config UART1_FULL_UART_ENABLED
+ bool "Configure UART1 as full UART (RX/TX/RTS/CTS/DCD/DTR/DSR/RI)"
+endchoice
+
+config UART1_IRDA_ENABLED
+ bool "Enable IRDA mode"
+ default n
+ depends on UART1_ENABLED
+ help
+ Enable IRDA mode
+
config UART2_ENABLED
bool "Enable UART2"
default y
- depends on SERIAL_MXC && MACH_CCWMX51JS
+ depends on SERIAL_MXC && MODULE_CCXMX51
help
Enable the MX51 UART2 interface
+config UART2_CTS_RTS_ENABLED
+ bool "Configure RTS/CTS lines for UART2 hardware flow control"
+ default n
+ depends on UART2_ENABLED
+ depends on !USB_EHCI_ARC_H1
+ help
+ Configure the UART2 RTS/CTS lines for hardware flow control operation
+
+comment "UART2 CTS/RTS is not available on the ConnectCore Wi-i.MX51 JumpStart board if"
+ depends on USB_EHCI_ARC_H1
+comment "the support for Host1 of the Freescale USB controller is enabled."
+ depends on USB_EHCI_ARC_H1
+
+config UART2_IRDA_ENABLED
+ bool "Enable IRDA mode"
+ default n
+ depends on UART2_ENABLED
+ help
+ Enable IRDA mode
+
+comment "UART3 is not available on the ConnectCore Wi-i.MX51 JumpStart board if UART1"
+ depends on UART1_FULL_UART_ENABLED
+comment "is configured as full UART. This may not be the case in a custom base board."
+ depends on UART1_FULL_UART_ENABLED
+
config UART3_ENABLED
bool "Enable UART3"
default y
- depends on SERIAL_MXC && MACH_CCWMX51JS
+ depends on SERIAL_MXC && MODULE_CCXMX51 && !UART1_FULL_UART_ENABLED
help
Enable the MX51 UART3 interface
+
+config UART3_CTS_RTS_ENABLED
+ bool "Configure RTS/CTS lines for UART3 hardware flow control"
+ default n
+ depends on UART3_ENABLED
+ help
+ Configure the UART3 RTS/CTS lines for hardware flow control operation
+
+config UART3_IRDA_ENABLED
+ bool "Enable IRDA mode"
+ default n
+ depends on UART3_ENABLED
+ help
+ Enable IRDA mode
+
endmenu
menu "SPI Interface Options"
config SPI_MXC_SELECT1
bool "Enable CSPI1"
- depends on SPI_MXC && MACH_CCWMX51JS
+ depends on SPI_MXC && MODULE_CCXMX51
default y
help
Enable the CSPI1 interface
config SPI_MXC_SELECT1_SS1
bool "Enable SS1 line for CSPI1"
- depends on SPI_MXC_SELECT1 && MACH_CCWMX51JS
+ depends on SPI_MXC_SELECT1 && MODULE_CCXMX51
default y
help
Enable SS1 (slave select 1) line, used on ConnectCore Wi-i.MX51 base board SPI connector
config SPI_MXC_SELECT2
bool "Enable CSPI2"
- depends on SPI_MXC && MACH_CCWMX51JS
+ depends on SPI_MXC && MODULE_CCXMX51
default n
help
Enable the CSPI2 interface
config SPI_MXC_SELECT3
bool "Enable CSPI3"
- depends on SPI_MXC && MACH_CCWMX51JS
+ depends on SPI_MXC && MODULE_CCXMX51
default n
help
Enable the CSPI3 interface
@@ -155,6 +299,7 @@ config I2C_MXC_SELECT1
bool "Enable I2C1 module"
default y
depends on I2C_MXC
+ depends on !MACH_CCWMX51JS
help
Enable MX51 I2C1 module.
@@ -174,4 +319,106 @@ config I2C_MXC_SELECT3
endmenu
-source "arch/arm/mach-mx5/displays/Kconfig" \ No newline at end of file
+menu "SD/MMC Interface options"
+
+config ESDHCI_MXC_SELECT1
+ bool "Enable SDHC 1"
+ default y
+ depends on MMC_IMX_ESDHCI
+ help
+ Enable the SD Host Controller 1.
+
+config ESDHCI_MXC_SELECT3
+ bool "Enable SDHC 3"
+ default y
+ depends on MMC_IMX_ESDHCI
+ help
+ Enable the SD Host Controller 3.
+
+endmenu
+
+if !FB_MXC_SYNC_PANEL
+comment "---Video interface disabled"
+endif
+
+if FB_MXC_SYNC_PANEL
+menu "Video Interface(s)"
+
+choice
+ prompt "Video color depth"
+ default CCWMX51_DEFAULT_VIDEO_32BPP
+ depends on MODULE_CCXMX51
+
+config CCWMX51_DEFAULT_VIDEO_32BPP
+ bool "32 bits per pixel"
+
+config CCWMX51_DEFAULT_VIDEO_16BPP
+ bool "16 bits per pixel"
+endchoice
+
+config CCWMX51_DEFAULT_VIDEO_BPP
+ int
+ depends on MODULE_CCXMX51
+ default 32 if CCWMX51_DEFAULT_VIDEO_32BPP
+ default 16 if CCWMX51_DEFAULT_VIDEO_16BPP
+
+config CCWMX51_DISP0
+ bool "Enable Display Interface 1 (primary)"
+ help
+ This enables the i.MX51 Display Interface 1.
+
+if CCWMX51_DISP0
+choice
+ prompt "Display 1 color mode"
+
+config CCWMX51_DISP0_RGB888
+ bool "24bit color mode"
+ depends on JSCCWMX51_V1
+ help
+ Configure Display 1 in 24bit color mode.
+
+ WARNING: The JumpStart Kit Development Board (30011032-02) is designed
+ to work in 18bit mode. To work in 24bit mode you need an Early Availability
+ Kit Development Board (30011032-01) or a custom designed board that
+ populates all 24 data lines of the video interface.
+
+ IMPORTANT: If Display 1 is configured for 24bit color depth, Display 2
+ will not be available.
+
+config CCWMX51_DISP0_RGB666
+ bool "18bit color mode"
+ depends on JSCCWMX51_V2
+ help
+ Configure Display 1 in 18bit color mode. Use this mode if working
+ on a JumpStart Kit Development Board.
+
+ WARNING: The Early Availability Development Board (30011032-01) is
+ designed to work in 24bit mode. To work in 18bit mode you need a
+ JumpStart Kit Development Board (30011032-02) or a custom designed
+ board that only populates 18 data lines of the video interface.
+
+endchoice
+endif
+
+comment "To enable the Display 2 Video interface, disable the FEC (under network drivers)"
+ depends on FEC || CCWMX51_DISP0_RGB888
+comment "and set 18bit color mode for the Display 1"
+ depends on FEC || CCWMX51_DISP0_RGB888
+
+config CCWMX51_DISP1
+ bool "Enable Display Interface 2 (secondary)"
+ depends on !FEC && !CCWMX51_DISP0_RGB888
+ help
+ This enables the i.MX51 Display Interface 2 (18bit color mode only).
+
+config CCWMX51_SECOND_TOUCH
+ bool "Enable support for external touch controller (ADS7843)"
+ depends on SPI_MXC_SELECT1
+ select TOUCHSCREEN_ADS7846
+ help
+ This enables the support for the external touch interface (ADS7843) available on the
+ High Resolution Display board, connected to the processor through SPI and that can be
+ used with the secondary display (but also with the primary)
+
+endmenu
+endif
diff --git a/arch/arm/mach-mx5/Makefile b/arch/arm/mach-mx5/Makefile
index 683ba5a78dc2..90baa14638fe 100644
--- a/arch/arm/mach-mx5/Makefile
+++ b/arch/arm/mach-mx5/Makefile
@@ -4,12 +4,21 @@
# Object file lists.
+obj-y := system.o iomux.o cpu.o mm.o devices.o serial.o dma.o lpmodes.o pm.o \
+sdram_autogating.o bus_freq.o usb_dr.o usb_h1.o usb_h2.o dummy_gpio.o early_setup.o
-obj-y := system.o iomux.o cpu.o mm.o clock.o devices.o serial.o dma.o lpmodes.o pm.o \
-sdram_autogating.o bus_freq.o usb_dr.o usb_h1.o usb_h2.o dummy_gpio.o wfi.o suspend.o
+-obj-$(CONFIG_ARCH_MX51) += clock.o
+-obj-$(CONFIG_ARCH_MX53) += clock.o
+-obj-$(CONFIG_ARCH_MX50) += clock_mx50.o
+obj-$(CONFIG_ARCH_MX51) += clock.o suspend.o
+obj-$(CONFIG_ARCH_MX53) += clock.o suspend.o
+obj-$(CONFIG_ARCH_MX50) += clock_mx50.o dmaengine.o dma-apbh.o mx50_suspend.o mx50_ddr_freq.o mx50_wfi.o
obj-$(CONFIG_MACH_MX51_3DS) += mx51_3stack.o mx51_3stack_gpio.o mx51_3stack_pmic_mc13892.o
-obj-$(CONFIG_MACH_MX51_BABBAGE) += mx51_babbage.o mx51_babbage_gpio.o mx51_babbage_pmic_mc13892.o
-obj-$(CONFIG_MACH_MX53_EVK) += mx53_evk.o mx53_evk_gpio.o mx53_evk_pmic_mc13892.o
+obj-$(CONFIG_MACH_MX51_BABBAGE) += mx51_babbage.o mx51_babbage_pmic_mc13892.o
+obj-$(CONFIG_MACH_MX53_EVK) += mx53_evk.o mx53_evk_pmic_mc13892.o
+obj-$(CONFIG_MACH_MX50_ARM2) += mx50_arm2.o mx50_arm2_pmic_mc13892.o
obj-$(CONFIG_MACH_CCWMX51JS) += devices_ccwmx51.o mx51_ccwmx51js.o mx51_ccwmx51js_gpio.o
+obj-$(CONFIG_MACH_CCMX51JS) += devices_ccwmx51.o mx51_ccwmx51js.o mx51_ccwmx51js_gpio.o
obj-$(CONFIG_MXC_PMIC_MC13892) += mx51_ccwmx51js_pmic_mc13892.o
+obj-$(CONFIG_MACH_MX50_RDP) += mx50_rdp.o mx50_rdp_pmic_mc13892.o
diff --git a/arch/arm/mach-mx5/Makefile.boot b/arch/arm/mach-mx5/Makefile.boot
index 741f60437582..434ef85a32dc 100644
--- a/arch/arm/mach-mx5/Makefile.boot
+++ b/arch/arm/mach-mx5/Makefile.boot
@@ -4,3 +4,6 @@ initrd_phys-$(CONFIG_ARCH_MX51) := 0x90800000
zreladdr-$(CONFIG_ARCH_MX53) := 0x70008000
params_phys-$(CONFIG_ARCH_MX53) := 0x70000100
initrd_phys-$(CONFIG_ARCH_MX53) := 0x70800000
+ zreladdr-$(CONFIG_ARCH_MX50) := 0x70008000
+params_phys-$(CONFIG_ARCH_MX50) := 0x70000100
+initrd_phys-$(CONFIG_ARCH_MX50) := 0x70800000
diff --git a/arch/arm/mach-mx5/board-ccwmx51.h b/arch/arm/mach-mx5/board-ccwmx51.h
index 6696c27c5c36..54376d190e82 100644
--- a/arch/arm/mach-mx5/board-ccwmx51.h
+++ b/arch/arm/mach-mx5/board-ccwmx51.h
@@ -20,8 +20,14 @@
#else
#define UART1_ENABLED 0
#endif
-#define UART1_MODE MODE_DCE
+#if defined CONFIG_UART1_IRDA_ENABLED
+#define UART1_IR IRDA
+#else
#define UART1_IR NO_IRDA
+#endif
+#define UART1_MODE MODE_DCE
+#define UART1_DMA_ENABLED 0
+
/* UART 2 configuration */
#if defined CONFIG_UART2_ENABLED
@@ -29,8 +35,13 @@
#else
#define UART2_ENABLED 0
#endif
-#define UART2_MODE MODE_DCE
+#if defined CONFIG_UART2_IRDA_ENABLED
+#define UART2_IR IRDA
+#else
#define UART2_IR NO_IRDA
+#endif
+#define UART2_MODE MODE_DCE
+#define UART2_DMA_ENABLED 0
/* UART 3 configuration */
#if defined CONFIG_UART3_ENABLED
@@ -38,19 +49,71 @@
#else
#define UART3_ENABLED 0
#endif
-#define UART3_MODE MODE_DCE
+#if defined CONFIG_UART3_IRDA_ENABLED
+#define UART3_IR IRDA
+#else
#define UART3_IR NO_IRDA
+#endif
+#define UART3_MODE MODE_DCE
+#define UART3_DMA_ENABLED 0
/*!
* Specifies if the Irda transmit path is inverting
*/
#define MXC_IRDA_TX_INV 0
-/*!
- * Specifies if the Irda receive path is inverting
- */
-#define MXC_IRDA_RX_INV 0
#define MXC_LL_UART_PADDR UART1_BASE_ADDR
#define MXC_LL_UART_VADDR AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
+/* Second touch interface configuration */
+#ifdef CONFIG_CCWMX51_SECOND_TOUCH
+#ifdef CONFIG_JSCCWMX51_V1
+/* Settings for the JSCCWMX51 Board RevA, for the DISP0 */
+#elif defined(CONFIG_JSCCWMX51_V2)
+/* Settings for the JSCCWMX51 Board RevB, for the DISP0/DISP1 */
+#endif /* CONFIG_JSCCWMX51_VX */
+#endif /* CONFIG_CCWMX51_SECOND_TOUCH */
+
+/* AD9389 interrupt */
+#ifdef CONFIG_JSCCWMX51_V1
+#define AD9389_GPIO_IRQ MX51_PIN_GPIO1_4
+#elif defined(CONFIG_JSCCWMX51_V2)
+#define AD9389_GPIO_IRQ MX51_PIN_GPIO1_0
+#endif
+
+
+/* Set Base board revision */
+#ifdef CONFIG_JSCCWMX51_V1
+/* Board revision and mach name postfix */
+#define BASE_BOARD_REV 1
+#define BOARD_NAME " on a EAK board"
+/* SD1 card detect irq */
+#define CCWMX51_SD1_CD_IRQ IOMUX_TO_IRQ(MX51_PIN_GPIO1_0)
+/* Second touch settings */
+#define SECOND_TS_IRQ_PIN MX51_PIN_DI1_D0_CS
+#define SECOND_TS_SPI_SS_PIN MX51_PIN_DI1_D1_CS
+#elif defined(CONFIG_JSCCWMX51_V2)
+/* Board revision */
+#define BASE_BOARD_REV 2
+#define BOARD_NAME " on a JSK board"
+/* SD1 card detect irq, not present CD line... */
+#define CCWMX51_SD1_CD_IRQ 0
+/* Second touch settings */
+#define SECOND_TS_IRQ_PIN MX51_PIN_DI1_D0_CS
+#define SECOND_TS_SPI_SS_PIN MX51_PIN_CSPI1_RDY
+#else
+#define BASE_BOARD_REV 0
+#define BOARD_NAME " on an undefined board"
+#endif
+
+/* framebuffer settings */
+#if defined(CONFIG_CCWMX51_DISP1) && defined(CONFIG_CCWMX51_DISP2)
+#define FB_MEM_SIZE SZ_32M
+#else
+#define FB_MEM_SIZE SZ_16M
+#endif
+
+void ccwmx51_2nd_touch_gpio_init(void);
+void ccwmx51_init_2nd_touch(void);
+
#endif /* __ASM_ARCH_MXC_BOARD_CCWMX51_H__ */
diff --git a/arch/arm/mach-mx5/bus_freq.c b/arch/arm/mach-mx5/bus_freq.c
index 4ab60ec6386d..ec2addfd977b 100644
--- a/arch/arm/mach-mx5/bus_freq.c
+++ b/arch/arm/mach-mx5/bus_freq.c
@@ -27,45 +27,56 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/iram_alloc.h>
+#include <linux/mutex.h>
#include <mach/hardware.h>
#include <mach/clock.h>
#include <mach/mxc_dvfs.h>
#include <mach/sdram_autogating.h>
+#include <asm/mach/map.h>
+#include <asm/cacheflush.h>
+#include <asm/tlb.h>
#include "crm_regs.h"
-#define LP_NORMAL_CLK 133000000
-#define LP_MED_CLK 83125000
+#define LP_LOW_VOLTAGE 1050000
+#define LP_NORMAL_VOLTAGE 1250000
#define LP_APM_CLK 24000000
#define NAND_LP_APM_CLK 12000000
-#define DDR_LOW_FREQ_CLK 133000000
-#define DDR_NORMAL_CLK 200000000
#define AXI_A_NORMAL_CLK 166250000
#define AXI_A_CLK_NORMAL_DIV 4
#define AXI_B_CLK_NORMAL_DIV 5
#define AHB_CLK_NORMAL_DIV AXI_B_CLK_NORMAL_DIV
#define EMI_SLOW_CLK_NORMAL_DIV AXI_B_CLK_NORMAL_DIV
#define NFC_CLK_NORMAL_DIV 4
+#define SPIN_DELAY 1000000 /* in nanoseconds */
+
+DEFINE_SPINLOCK(ddr_freq_lock);
+
+static unsigned long lp_normal_rate;
+static unsigned long lp_med_rate;
+static unsigned long ddr_normal_rate;
+static unsigned long ddr_low_rate;
static struct clk *ddr_clk;
+static struct clk *pll1_sw_clk;
+static struct clk *pll1;
static struct clk *pll2;
static struct clk *pll3;
+static struct clk *pll4;
static struct clk *main_bus_clk;
static struct clk *axi_a_clk;
static struct clk *axi_b_clk;
static struct clk *cpu_clk;
static struct clk *ddr_hf_clk;
-static struct clk *nfc_clk;
static struct clk *ahb_clk;
-static struct clk *vpu_clk;
-static struct clk *vpu_core_clk;
-static struct clk *emi_slow_clk;
static struct clk *ddr_clk;
-static struct clk *ipu_clk;
static struct clk *periph_apm_clk;
static struct clk *lp_apm;
static struct clk *osc;
static struct clk *gpc_dvfs_clk;
static struct clk *emi_garb_clk;
+static void __iomem *pll1_base;
+static void __iomem *pll4_base;
struct regulator *lp_regulator;
int low_bus_freq_mode;
@@ -77,14 +88,28 @@ char *lp_reg_id = "SW2";
static struct cpu_wp *cpu_wp_tbl;
static struct device *busfreq_dev;
static int busfreq_suspended;
+static int cpu_podf;
/* True if bus_frequency is scaled not using DVFS-PER */
int bus_freq_scaling_is_active;
-extern int lp_high_freq;
-extern int lp_med_freq;
+int cpu_wp_nr;
+int lp_high_freq;
+int lp_med_freq;
+
+void enter_lpapm_mode_mx50(void);
+void enter_lpapm_mode_mx51(void);
+void exit_lpapm_mode_mx50(void);
+void exit_lpapm_mode_mx51(void);
+void *ddr_freq_change_iram_base;
+void (*change_ddr_freq)(void *ccm_addr, void *databahn_addr, u32 freq) = NULL;
+
+extern void mx50_ddr_freq_change(u32 ccm_base,
+ u32 databahn_addr, u32 freq);
extern int dvfs_core_is_active;
extern struct cpu_wp *(*get_cpu_wp)(int *wp);
-extern int cpu_wp_nr;
+extern void propagate_rate(struct clk *tclk);
+extern void __iomem *ccm_base;
+extern void __iomem *databahn_base;
struct dvfs_wp dvfs_core_setpoint[] = {
{33, 8, 33, 10, 10, 0x08},
@@ -92,121 +117,267 @@ struct dvfs_wp dvfs_core_setpoint[] = {
{28, 8, 33, 20, 30, 0x08},
{29, 0, 33, 20, 10, 0x08},};
-
int set_low_bus_freq(void)
{
u32 reg;
+ struct timespec nstimeofday;
+ struct timespec curtime;
if (busfreq_suspended)
return 0;
if (bus_freq_scaling_initialized) {
- if (clk_get_rate(cpu_clk) != cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate)
+ /* can not enter low bus freq, when cpu is in highest freq */
+ if (clk_get_rate(cpu_clk) !=
+ cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate) {
return 0;
+ }
stop_dvfs_per();
stop_sdram_autogating();
- /*Change the DDR freq to 133Mhz. */
- clk_set_rate(ddr_hf_clk,
- clk_round_rate(ddr_hf_clk, DDR_LOW_FREQ_CLK));
-
/* Set PLL3 to 133Mhz if no-one is using it. */
- if (clk_get_usecount(pll3) == 0) {
+ if ((clk_get_usecount(pll3) == 0) && !cpu_is_mx53()) {
u32 pll3_rate = clk_get_rate(pll3);
clk_enable(pll3);
clk_set_rate(pll3, clk_round_rate(pll3, 133000000));
- /* Set the parent of Periph_apm_clk to be PLL3 */
- clk_set_parent(periph_apm_clk, pll3);
- clk_set_parent(main_bus_clk, periph_apm_clk);
-
- /* Set the AHB dividers to be 1. */
- /* Set the dividers to be 1, so the clock rates
- * are at 133MHz.
- */
- reg = __raw_readl(MXC_CCM_CBCDR);
- reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK
- | MXC_CCM_CBCDR_AXI_B_PODF_MASK
- | MXC_CCM_CBCDR_AHB_PODF_MASK
- | MXC_CCM_CBCDR_EMI_PODF_MASK
- | MXC_CCM_CBCDR_NFC_PODF_OFFSET);
- reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
- | 0 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
- | 0 << MXC_CCM_CBCDR_AHB_PODF_OFFSET
- | 0 << MXC_CCM_CBCDR_EMI_PODF_OFFSET
- | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET);
- __raw_writel(reg, MXC_CCM_CBCDR);
-
- clk_enable(emi_garb_clk);
- while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F)
- udelay(10);
- clk_disable(emi_garb_clk);
-
- /* Set the source of Periph_APM_Clock to be lp-apm. */
- clk_set_parent(periph_apm_clk, lp_apm);
+ if (cpu_is_mx50())
+ enter_lpapm_mode_mx50();
+ else
+ enter_lpapm_mode_mx51();
/* Set PLL3 back to original rate. */
clk_set_rate(pll3, clk_round_rate(pll3, pll3_rate));
clk_disable(pll3);
+ } else if (cpu_is_mx53()) {
+ /*Change the DDR freq to 133Mhz. */
+ clk_set_rate(ddr_hf_clk,
+ clk_round_rate(ddr_hf_clk, ddr_low_rate));
+
+ /* move cpu clk to pll2, 400 / 3 = 133Mhz for cpu */
+ clk_set_parent(pll1_sw_clk, pll2);
+
+ cpu_podf = __raw_readl(MXC_CCM_CACRR);
+ reg = __raw_readl(MXC_CCM_CDHIPR);
+ if ((reg & MXC_CCM_CDHIPR_ARM_PODF_BUSY) == 0)
+ __raw_writel(0x2, MXC_CCM_CACRR);
+ else
+ printk(KERN_DEBUG "ARM_PODF still in busy!!!!\n");
+
+ /* ahb = 400/8, axi_b = 400/8, axi_a = 133*/
+ reg = __raw_readl(MXC_CCM_CBCDR);
+ reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK
+ | MXC_CCM_CBCDR_AXI_B_PODF_MASK
+ | MXC_CCM_CBCDR_AHB_PODF_MASK);
+ reg |= (2 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
+ | 7 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
+ | 7 << MXC_CCM_CBCDR_AHB_PODF_OFFSET);
+ __raw_writel(reg, MXC_CCM_CBCDR);
+
+ getnstimeofday(&nstimeofday);
+ while (__raw_readl(MXC_CCM_CDHIPR) &
+ (MXC_CCM_CDHIPR_AXI_A_PODF_BUSY |
+ MXC_CCM_CDHIPR_AXI_B_PODF_BUSY |
+ MXC_CCM_CDHIPR_AHB_PODF_BUSY)) {
+ getnstimeofday(&curtime);
+ if (curtime.tv_nsec - nstimeofday.tv_nsec
+ > SPIN_DELAY)
+ panic("low bus freq set rate error\n");
+ }
+
+ /* keep this infront of propagating */
low_bus_freq_mode = 1;
high_bus_freq_mode = 0;
+
+ propagate_rate(main_bus_clk);
+ propagate_rate(pll1_sw_clk);
+
+ if (clk_get_usecount(pll1) == 0) {
+ reg = __raw_readl(pll1_base + MXC_PLL_DP_CTL);
+ reg &= ~MXC_PLL_DP_CTL_UPEN;
+ __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL);
+ }
+ if (clk_get_usecount(pll4) == 0) {
+ reg = __raw_readl(pll4_base + MXC_PLL_DP_CTL);
+ reg &= ~MXC_PLL_DP_CTL_UPEN;
+ __raw_writel(reg, pll4_base + MXC_PLL_DP_CTL);
+ }
}
}
return 0;
}
+void enter_lpapm_mode_mx50()
+{
+ u32 reg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ddr_freq_lock, flags);
+
+ /* Set the parent of main_bus_clk to be PLL3 */
+ clk_set_parent(main_bus_clk, pll3);
+
+ /* Set the AHB dividers to be 1. */
+ /* Set the dividers to be 1, so the clock rates
+ * are at 133MHz.
+ */
+ reg = __raw_readl(MXC_CCM_CBCDR);
+ reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK
+ | MXC_CCM_CBCDR_AXI_B_PODF_MASK
+ | MXC_CCM_CBCDR_AHB_PODF_MASK
+ | MX50_CCM_CBCDR_WEIM_PODF_MASK);
+ reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
+ | 0 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
+ | 0 << MXC_CCM_CBCDR_AHB_PODF_OFFSET
+ | 0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET);
+ __raw_writel(reg, MXC_CCM_CBCDR);
+ while (__raw_readl(MXC_CCM_CDHIPR) & 0x0F)
+ udelay(10);
+ low_bus_freq_mode = 1;
+ high_bus_freq_mode = 0;
+
+ /* Set the source of main_bus_clk to be lp-apm. */
+ clk_set_parent(main_bus_clk, lp_apm);
+
+ /* Set SYS_CLK to 24MHz. sourced from XTAL*/
+ /* Turn on the XTAL_CLK_GATE. */
+ reg = __raw_readl(MXC_CCM_CLK_SYS);
+ reg |= 3 << MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_OFFSET;
+ __raw_writel(reg, MXC_CCM_CLK_SYS);
+
+ /* Set the divider. */
+ reg = __raw_readl(MXC_CCM_CLK_SYS);
+ reg &= ~MXC_CCM_CLK_SYS_DIV_XTAL_MASK;
+ reg |= 1 << MXC_CCM_CLK_SYS_DIV_XTAL_OFFSET;
+ __raw_writel(reg, MXC_CCM_CLK_SYS);
+ while (__raw_readl(MXC_CCM_CSR2) & 0x1)
+ udelay(10);
+
+ /* Set the source to be XTAL. */
+ reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS);
+ reg &= ~0x1;
+ __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS);
+ while (!(__raw_readl(MXC_CCM_CSR2) & 0x400))
+ udelay(10);
+
+ /* Turn OFF the PLL_CLK_GATE. */
+ reg = __raw_readl(MXC_CCM_CLK_SYS);
+ reg &= ~MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_MASK;
+ __raw_writel(reg, MXC_CCM_CLK_SYS);
+ spin_unlock_irqrestore(&ddr_freq_lock, flags);
+
+}
+
+void enter_lpapm_mode_mx51()
+{
+ u32 reg;
+
+ /*Change the DDR freq to 133Mhz. */
+ clk_set_rate(ddr_hf_clk,
+ clk_round_rate(ddr_hf_clk, ddr_low_rate));
+
+ /* Set the parent of Periph_apm_clk to be PLL3 */
+ clk_set_parent(periph_apm_clk, pll3);
+ clk_set_parent(main_bus_clk, periph_apm_clk);
+
+ /* Set the dividers to be 1, so the clock rates
+ * are at 133MHz.
+ */
+ reg = __raw_readl(MXC_CCM_CBCDR);
+ reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK
+ | MXC_CCM_CBCDR_AXI_B_PODF_MASK
+ | MXC_CCM_CBCDR_AHB_PODF_MASK
+ | MXC_CCM_CBCDR_EMI_PODF_MASK
+ | MXC_CCM_CBCDR_NFC_PODF_OFFSET);
+ reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
+ | 0 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
+ | 0 << MXC_CCM_CBCDR_AHB_PODF_OFFSET
+ | 0 << MXC_CCM_CBCDR_EMI_PODF_OFFSET
+ | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET);
+ __raw_writel(reg, MXC_CCM_CBCDR);
+
+ clk_enable(emi_garb_clk);
+ while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F)
+ udelay(10);
+ clk_disable(emi_garb_clk);
+
+ /* Set the source of Periph_APM_Clock to be lp-apm. */
+ clk_set_parent(periph_apm_clk, lp_apm);
+}
+
int set_high_bus_freq(int high_bus_freq)
{
u32 reg;
+ struct timespec nstimeofday;
+ struct timespec curtime;
if (bus_freq_scaling_initialized) {
+
stop_sdram_autogating();
if (low_bus_freq_mode) {
/* Relock PLL3 to 133MHz */
- if (clk_get_usecount(pll3) == 0) {
+ if ((clk_get_usecount(pll3) == 0) && !cpu_is_mx53()) {
u32 pll3_rate = clk_get_rate(pll3);
clk_enable(pll3);
clk_set_rate(pll3,
clk_round_rate(pll3, 133000000));
- clk_set_parent(periph_apm_clk, pll3);
- /* Set the dividers to the default dividers */
+ if (cpu_is_mx50())
+ exit_lpapm_mode_mx50();
+ else
+ exit_lpapm_mode_mx51();
+
+ /* Relock PLL3 to its original rate */
+ clk_set_rate(pll3,
+ clk_round_rate(pll3, pll3_rate));
+ clk_disable(pll3);
+ } else if (cpu_is_mx53()) {
+ /* move cpu clk to pll1 */
+ reg = __raw_readl(MXC_CCM_CDHIPR);
+ if ((reg & MXC_CCM_CDHIPR_ARM_PODF_BUSY) == 0)
+ __raw_writel(cpu_podf & 0x7,
+ MXC_CCM_CACRR);
+ else
+ printk(KERN_DEBUG
+ "ARM_PODF still in busy!!!!\n");
+
+ clk_set_parent(pll1_sw_clk, pll1);
+
+ /* ahb = 400/3, axi_b = 400/3, axi_a = 400*/
reg = __raw_readl(MXC_CCM_CBCDR);
reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK
| MXC_CCM_CBCDR_AXI_B_PODF_MASK
- | MXC_CCM_CBCDR_AHB_PODF_MASK
- | MXC_CCM_CBCDR_EMI_PODF_MASK
- | MXC_CCM_CBCDR_NFC_PODF_OFFSET);
- reg |= (3 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
- | 4 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
- | 4 << MXC_CCM_CBCDR_AHB_PODF_OFFSET
- | 4 << MXC_CCM_CBCDR_EMI_PODF_OFFSET
- | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET);
+ | MXC_CCM_CBCDR_AHB_PODF_MASK);
+ reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
+ | 2 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
+ | 2 << MXC_CCM_CBCDR_AHB_PODF_OFFSET);
__raw_writel(reg, MXC_CCM_CBCDR);
- clk_enable(emi_garb_clk);
- while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F)
- udelay(10);
-
- low_bus_freq_mode = 0;
- high_bus_freq_mode = 1;
- clk_disable(emi_garb_clk);
-
- /*Set the main_bus_clk parent to be PLL2. */
- clk_set_parent(main_bus_clk, pll2);
+ getnstimeofday(&nstimeofday);
+ while (__raw_readl(MXC_CCM_CDHIPR) &
+ (MXC_CCM_CDHIPR_AXI_A_PODF_BUSY |
+ MXC_CCM_CDHIPR_AXI_B_PODF_BUSY |
+ MXC_CCM_CDHIPR_AHB_PODF_BUSY)) {
+ getnstimeofday(&curtime);
+ if (curtime.tv_nsec
+ - nstimeofday.tv_nsec
+ > SPIN_DELAY)
+ panic("bus freq error\n");
+ }
+
+ /* keep this infront of propagating */
+ low_bus_freq_mode = 1;
+ high_bus_freq_mode = 0;
- /* Relock PLL3 to its original rate */
- clk_set_rate(pll3,
- clk_round_rate(pll3, pll3_rate));
- clk_disable(pll3);
+ propagate_rate(main_bus_clk);
+ propagate_rate(pll1_sw_clk);
+ /*Change the DDR freq to mormal_rate*/
+ clk_set_rate(ddr_hf_clk,
+ clk_round_rate(ddr_hf_clk, ddr_normal_rate));
}
-
- /*Change the DDR freq to 200MHz*/
- clk_set_rate(ddr_hf_clk,
- clk_round_rate(ddr_hf_clk, DDR_NORMAL_CLK));
start_dvfs_per();
}
if (bus_freq_scaling_is_active) {
@@ -218,24 +389,28 @@ int set_high_bus_freq(int high_bus_freq)
cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate)
high_bus_freq = 1;
- if (((clk_get_rate(ahb_clk) == LP_MED_CLK)
+ if (((clk_get_rate(ahb_clk) == lp_med_rate)
&& lp_high_freq) || high_bus_freq) {
/* Set to the high setpoint. */
high_bus_freq_mode = 1;
+
clk_set_rate(ahb_clk,
- clk_round_rate(ahb_clk, LP_NORMAL_CLK));
+ clk_round_rate(ahb_clk, lp_normal_rate));
+
clk_set_rate(ddr_hf_clk,
- clk_round_rate(ddr_hf_clk, DDR_NORMAL_CLK));
+ clk_round_rate(ddr_hf_clk, ddr_normal_rate));
}
+
if (!lp_high_freq && !high_bus_freq) {
/* Set to the medium setpoint. */
high_bus_freq_mode = 0;
low_bus_freq_mode = 0;
+
clk_set_rate(ddr_hf_clk,
- clk_round_rate(ddr_hf_clk,
- DDR_LOW_FREQ_CLK));
+ clk_round_rate(ddr_hf_clk, ddr_low_rate));
+
clk_set_rate(ahb_clk,
- clk_round_rate(ahb_clk, LP_MED_CLK));
+ clk_round_rate(ahb_clk, lp_med_rate));
}
}
start_sdram_autogating();
@@ -243,11 +418,105 @@ int set_high_bus_freq(int high_bus_freq)
return 0;
}
+void exit_lpapm_mode_mx50()
+{
+ u32 reg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ddr_freq_lock, flags);
+
+ /* Set SYS_CLK to source from PLL1 */
+ /* Set sys_clk back to 200MHz. */
+ /* Set the divider to 4. */
+ reg = __raw_readl(MXC_CCM_CLK_SYS);
+ reg &= ~MXC_CCM_CLK_SYS_DIV_PLL_MASK;
+ reg |= 0x4 << MXC_CCM_CLK_SYS_DIV_PLL_OFFSET;
+ __raw_writel(reg, MXC_CCM_CLK_SYS);
+ udelay(100);
+
+ /* Turn ON the PLL CLK_GATE. */
+ reg = __raw_readl(MXC_CCM_CLK_SYS);
+ reg |= 3 << MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_OFFSET;
+ __raw_writel(reg, MXC_CCM_CLK_SYS);
+
+ /* Source the SYS_CLK from PLL */
+ reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS);
+ reg |= 0x3;
+ __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS);
+ while (__raw_readl(MXC_CCM_CSR2) & 0x400)
+ udelay(10);
+
+ /* Turn OFF the XTAL_CLK_GATE. */
+ reg = __raw_readl(MXC_CCM_CLK_SYS);
+ reg &= ~MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_MASK;
+ __raw_writel(reg, MXC_CCM_CLK_SYS);
+
+ clk_set_parent(main_bus_clk, pll3);
+
+ /* Set the dividers to the default dividers */
+ reg = __raw_readl(MXC_CCM_CBCDR);
+ reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK
+ | MXC_CCM_CBCDR_AXI_B_PODF_MASK
+ | MXC_CCM_CBCDR_AHB_PODF_MASK
+ | MX50_CCM_CBCDR_WEIM_PODF_MASK);
+ reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
+ |1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
+ |2 << MXC_CCM_CBCDR_AHB_PODF_OFFSET
+ |0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET);
+ __raw_writel(reg, MXC_CCM_CBCDR);
+
+ while (__raw_readl(MXC_CCM_CDHIPR) & 0xF)
+ udelay(10);
+
+ low_bus_freq_mode = 0;
+ high_bus_freq_mode = 1;
+
+ /*Set the main_bus_clk parent to be PLL2. */
+ clk_set_parent(main_bus_clk, pll2);
+ spin_unlock_irqrestore(&ddr_freq_lock, flags);
+
+ udelay(100);
+}
+
+void exit_lpapm_mode_mx51()
+{
+ u32 reg;
+
+ clk_set_parent(periph_apm_clk, pll3);
+
+ /* Set the dividers to the default dividers */
+ reg = __raw_readl(MXC_CCM_CBCDR);
+ reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK
+ | MXC_CCM_CBCDR_AXI_B_PODF_MASK
+ | MXC_CCM_CBCDR_AHB_PODF_MASK
+ | MXC_CCM_CBCDR_EMI_PODF_MASK
+ | MXC_CCM_CBCDR_NFC_PODF_OFFSET);
+ reg |= (3 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
+ | 4 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
+ | 4 << MXC_CCM_CBCDR_AHB_PODF_OFFSET
+ | 4 << MXC_CCM_CBCDR_EMI_PODF_OFFSET
+ | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET);
+ __raw_writel(reg, MXC_CCM_CBCDR);
+
+ clk_enable(emi_garb_clk);
+ while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F)
+ udelay(10);
+
+ low_bus_freq_mode = 0;
+ high_bus_freq_mode = 1;
+ clk_disable(emi_garb_clk);
+
+ /*Set the main_bus_clk parent to be PLL2. */
+ clk_set_parent(main_bus_clk, pll2);
+
+ /*Change the DDR freq to 200MHz*/
+ clk_set_rate(ddr_hf_clk,
+ clk_round_rate(ddr_hf_clk, ddr_normal_rate));
+}
+
int low_freq_bus_used(void)
{
- if ((clk_get_usecount(ipu_clk) == 0)
- && (clk_get_usecount(vpu_clk) == 0)
- && (lp_high_freq == 0)
+ if ((lp_high_freq == 0)
&& (lp_med_freq == 0))
return 1;
else
@@ -273,8 +542,7 @@ static ssize_t bus_freq_scaling_enable_store(struct device *dev,
{
u32 reg;
-
- if (strstr(buf, "1") != NULL) {
+ if (strncmp(buf, "1", 1) == 0) {
if (dvfs_per_active()) {
printk(KERN_INFO "bus frequency scaling cannot be\
enabled when DVFS-PER is active\n");
@@ -288,12 +556,13 @@ static ssize_t bus_freq_scaling_enable_store(struct device *dev,
clk_set_parent(main_bus_clk, pll2);
bus_freq_scaling_is_active = 1;
- }
- else if (strstr(buf, "0") != NULL) {
+ set_high_bus_freq(0);
+ } else if (strncmp(buf, "0", 1) == 0) {
if (bus_freq_scaling_is_active)
set_high_bus_freq(1);
bus_freq_scaling_is_active = 0;
}
+
return size;
}
@@ -325,6 +594,12 @@ static DEVICE_ATTR(enable, 0644, bus_freq_scaling_enable_show,
static int __devinit busfreq_probe(struct platform_device *pdev)
{
int err = 0;
+ unsigned long pll2_rate, pll1_rate;
+ unsigned long iram_paddr;
+
+ pll1_base = ioremap(MX53_BASE_ADDR(PLL1_BASE_ADDR), SZ_4K);
+ if (cpu_is_mx53())
+ pll4_base = ioremap(MX53_BASE_ADDR(PLL4_BASE_ADDR), SZ_4K);
busfreq_dev = &pdev->dev;
@@ -335,6 +610,18 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
return PTR_ERR(main_bus_clk);
}
+ pll1_sw_clk = clk_get(NULL, "pll1_sw_clk");
+ if (IS_ERR(pll1_sw_clk)) {
+ printk(KERN_DEBUG "%s: failed to get pll1_sw_clk\n", __func__);
+ return PTR_ERR(pll1_sw_clk);
+ }
+
+ pll1 = clk_get(NULL, "pll1_main_clk");
+ if (IS_ERR(pll1)) {
+ printk(KERN_DEBUG "%s: failed to get pll1\n", __func__);
+ return PTR_ERR(pll1);
+ }
+
pll2 = clk_get(NULL, "pll2");
if (IS_ERR(pll2)) {
printk(KERN_DEBUG "%s: failed to get pll2\n", __func__);
@@ -347,6 +634,14 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
return PTR_ERR(pll3);
}
+ if (cpu_is_mx53()) {
+ pll4 = clk_get(NULL, "pll4");
+ if (IS_ERR(pll4)) {
+ printk(KERN_DEBUG "%s: failed to get pll4\n", __func__);
+ return PTR_ERR(pll4);
+ }
+ }
+
axi_a_clk = clk_get(NULL, "axi_a_clk");
if (IS_ERR(axi_a_clk)) {
printk(KERN_DEBUG "%s: failed to get axi_a_clk\n",
@@ -361,25 +656,19 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
return PTR_ERR(axi_b_clk);
}
- ddr_hf_clk = clk_get(NULL, "ddr_hf_clk");
- if (IS_ERR(ddr_hf_clk)) {
- printk(KERN_DEBUG "%s: failed to get ddr_hf_clk\n",
+ ddr_clk = clk_get(NULL, "ddr_clk");
+ if (IS_ERR(ddr_clk)) {
+ printk(KERN_DEBUG "%s: failed to get ddr_clk\n",
__func__);
- return PTR_ERR(ddr_hf_clk);
+ return PTR_ERR(ddr_clk);
}
- emi_slow_clk = clk_get(NULL, "emi_slow_clk");
- if (IS_ERR(emi_slow_clk)) {
- printk(KERN_DEBUG "%s: failed to get emi_slow_clk\n",
- __func__);
- return PTR_ERR(emi_slow_clk);
- }
+ ddr_hf_clk = clk_get_parent(ddr_clk);
- nfc_clk = clk_get(NULL, "nfc_clk");
- if (IS_ERR(nfc_clk)) {
- printk(KERN_DEBUG "%s: failed to get nfc_clk\n",
+ if (IS_ERR(ddr_hf_clk)) {
+ printk(KERN_DEBUG "%s: failed to get ddr_hf_clk\n",
__func__);
- return PTR_ERR(nfc_clk);
+ return PTR_ERR(ddr_hf_clk);
}
ahb_clk = clk_get(NULL, "ahb_clk");
@@ -389,20 +678,6 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
return PTR_ERR(ahb_clk);
}
- vpu_core_clk = clk_get(NULL, "vpu_core_clk");
- if (IS_ERR(vpu_core_clk)) {
- printk(KERN_DEBUG "%s: failed to get vpu_core_clk\n",
- __func__);
- return PTR_ERR(vpu_core_clk);
- }
-
- ddr_clk = clk_get(NULL, "ddr_clk");
- if (IS_ERR(ddr_clk)) {
- printk(KERN_DEBUG "%s: failed to get ddr_clk\n",
- __func__);
- return PTR_ERR(ddr_clk);
- }
-
cpu_clk = clk_get(NULL, "cpu_clk");
if (IS_ERR(cpu_clk)) {
printk(KERN_DEBUG "%s: failed to get cpu_clk\n",
@@ -410,35 +685,25 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
return PTR_ERR(cpu_clk);
}
- ipu_clk = clk_get(NULL, "ipu_clk");
- if (IS_ERR(ipu_clk)) {
- printk(KERN_DEBUG "%s: failed to get ipu_clk\n",
- __func__);
- return PTR_ERR(ipu_clk);
- }
-
if (cpu_is_mx51())
emi_garb_clk = clk_get(NULL, "emi_garb_clk");
- else
+ else if (cpu_is_mx53())
emi_garb_clk = clk_get(NULL, "emi_intr_clk.1");
+ else
+ emi_garb_clk = clk_get(NULL, "ocram_clk");
if (IS_ERR(emi_garb_clk)) {
printk(KERN_DEBUG "%s: failed to get emi_garb_clk\n",
__func__);
return PTR_ERR(emi_garb_clk);
}
- vpu_clk = clk_get(NULL, "vpu_clk");
- if (IS_ERR(vpu_clk)) {
- printk(KERN_DEBUG "%s: failed to get vpu_clk\n",
- __func__);
- return PTR_ERR(vpu_clk);
- }
-
- periph_apm_clk = clk_get(NULL, "periph_apm_clk");
- if (IS_ERR(periph_apm_clk)) {
- printk(KERN_DEBUG "%s: failed to get periph_apm_clk\n",
- __func__);
- return PTR_ERR(periph_apm_clk);
+ if (cpu_is_mx51() || cpu_is_mx53()) {
+ periph_apm_clk = clk_get(NULL, "periph_apm_clk");
+ if (IS_ERR(periph_apm_clk)) {
+ printk(KERN_DEBUG "%s: failed to get periph_apm_clk\n",
+ __func__);
+ return PTR_ERR(periph_apm_clk);
+ }
}
lp_apm = clk_get(NULL, "lp_apm");
@@ -467,6 +732,49 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
return err;
}
+ pll1_rate = clk_get_rate(pll1_sw_clk);
+ pll2_rate = clk_get_rate(pll2);
+
+ if (pll2_rate == 665000000) {
+ /* for mx51 */
+ lp_normal_rate = pll2_rate / 5;
+ lp_med_rate = pll2_rate / 8;
+ ddr_normal_rate = pll1_rate / 4; /* 200M */
+ ddr_low_rate = pll1_rate / 6; /* 133M */
+ } else if (pll2_rate == 600000000) {
+ /* for mx53 evk rev.A */
+ lp_normal_rate = pll2_rate / 5;
+ lp_med_rate = pll2_rate / 8;
+ ddr_normal_rate = pll2_rate / 2;
+ ddr_low_rate = pll2_rate / 2;
+ } else if (pll2_rate == 400000000) {
+ /* for mx53 evk rev.B */
+ lp_normal_rate = pll2_rate / 3;
+ lp_med_rate = pll2_rate / 5;
+ if (cpu_is_mx53()) {
+ ddr_normal_rate = pll2_rate / 1;
+ ddr_low_rate = pll2_rate / 3;
+ } else if (cpu_is_mx50()) {
+ ddr_normal_rate = clk_get_rate(ddr_clk);
+ ddr_low_rate = LP_APM_CLK;
+ }
+ }
+ if (cpu_is_mx50()) {
+ iram_alloc(SZ_8K, &iram_paddr);
+ /* Need to remap the area here since we want the memory region
+ to be executable. */
+ ddr_freq_change_iram_base = __arm_ioremap(iram_paddr,
+ SZ_8K, MT_HIGH_VECTORS);
+ memcpy(ddr_freq_change_iram_base, mx50_ddr_freq_change, SZ_8K);
+ change_ddr_freq = (void *)ddr_freq_change_iram_base;
+
+ lp_regulator = regulator_get(NULL, "SW2");
+ if (IS_ERR(lp_regulator)) {
+ printk(KERN_DEBUG
+ "%s: failed to get lp regulator\n", __func__);
+ return PTR_ERR(lp_regulator);
+ }
+ }
cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr);
low_bus_freq_mode = 0;
high_bus_freq_mode = 1;
diff --git a/arch/arm/mach-mx5/clock.c b/arch/arm/mach-mx5/clock.c
index 7c6f614bf97f..5ec89a6570cd 100644
--- a/arch/arm/mach-mx5/clock.c
+++ b/arch/arm/mach-mx5/clock.c
@@ -42,6 +42,7 @@ static struct clk emi_slow_clk;
static struct clk emi_intr_clk[];
static struct clk ddr_clk;
static struct clk ipu_clk[];
+static struct clk ldb_di_clk[];
static struct clk axi_a_clk;
static struct clk axi_b_clk;
static struct clk ddr_hf_clk;
@@ -52,16 +53,26 @@ static struct clk vpu_clk[];
static int cpu_curr_wp;
static struct cpu_wp *cpu_wp_tbl;
-void __iomem *pll1_base;
-void __iomem *pll2_base;
-void __iomem *pll3_base;
-void __iomem *pll4_base;
+static void __iomem *pll1_base;
+static void __iomem *pll2_base;
+static void __iomem *pll3_base;
+static void __iomem *pll4_base;
+
+extern int cpu_wp_nr;
+extern int lp_high_freq;
+extern int lp_med_freq;
+int max_axi_a_clk;
+int max_axi_b_clk;
-int cpu_wp_nr;
-int lp_high_freq;
-int lp_med_freq;
#define SPIN_DELAY 1000000 /* in nanoseconds */
+#define MAX_AXI_A_CLK_MX51 166250000
+#define MAX_AXI_A_CLK_MX53 400000000
+#define MAX_AXI_B_CLK_MX51 133000000
+#define MAX_AXI_B_CLK_MX53 200000000
+#define MAX_AHB_CLK 133000000
+#define MAX_EMI_SLOW_CLK 133000000
+#define MAX_DDR_HF_RATE 200000000
extern int mxc_jtag_enabled;
extern int uart_at_24;
@@ -70,8 +81,8 @@ extern int low_bus_freq_mode;
static int cpu_clk_set_wp(int wp);
extern void propagate_rate(struct clk *tclk);
-struct cpu_wp *(*get_cpu_wp)(int *wp);
-void (*set_num_cpu_wp)(int num);
+extern struct cpu_wp *(*get_cpu_wp)(int *wp);
+extern void (*set_num_cpu_wp)(int num);
static struct clk esdhc3_clk[];
@@ -394,7 +405,12 @@ static int _clk_pll_enable(struct clk *clk)
struct timespec curtime;
pllbase = _get_pll_base(clk);
- reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) | MXC_PLL_DP_CTL_UPEN;
+ reg = __raw_readl(pllbase + MXC_PLL_DP_CTL);
+
+ if (reg & MXC_PLL_DP_CTL_UPEN)
+ return 0;
+
+ reg |= MXC_PLL_DP_CTL_UPEN;
__raw_writel(reg, pllbase + MXC_PLL_DP_CTL);
/* Wait for lock */
@@ -738,10 +754,18 @@ static unsigned long _clk_axi_a_round_rate(struct clk *clk,
u32 div;
div = clk->parent->rate / rate;
+
+ /* Make sure rate is not greater than the maximum value for the clock.
+ * Also prevent a div of 0.
+ */
+ if (div == 0)
+ div++;
+ if (clk->parent->rate / div > max_axi_a_clk)
+ div++;
+
if (div > 8)
div = 8;
- else if (div == 0)
- div++;
+
return clk->parent->rate / div;
}
@@ -771,10 +795,18 @@ static unsigned long _clk_ddr_hf_round_rate(struct clk *clk,
u32 div;
div = clk->parent->rate / rate;
+
+ /* Make sure rate is not greater than the maximum value for the clock.
+ * Also prevent a div of 0.
+ */
+ if (div == 0)
+ div++;
+ if (clk->parent->rate / div > MAX_DDR_HF_RATE)
+ div++;
+
if (div > 8)
div = 8;
- else if (div == 0)
- div++;
+
return clk->parent->rate / div;
}
@@ -875,10 +907,18 @@ static unsigned long _clk_axi_b_round_rate(struct clk *clk,
u32 div;
div = clk->parent->rate / rate;
+
+ /* Make sure rate is not greater than the maximum value for the clock.
+ * Also prevent a div of 0.
+ */
+ if (div == 0)
+ div++;
+ if (clk->parent->rate / div > max_axi_b_clk)
+ div++;
+
if (div > 8)
div = 8;
- else if (div == 0)
- div++;
+
return clk->parent->rate / div;
}
@@ -945,10 +985,18 @@ static unsigned long _clk_ahb_round_rate(struct clk *clk,
u32 div;
div = clk->parent->rate / rate;
+
+ /* Make sure rate is not greater than the maximum value for the clock.
+ * Also prevent a div of 0.
+ */
+ if (div == 0)
+ div++;
+ if (clk->parent->rate / div > MAX_AHB_CLK)
+ div++;
+
if (div > 8)
div = 8;
- else if (div == 0)
- div++;
+
return clk->parent->rate / div;
}
@@ -973,7 +1021,7 @@ static int _clk_max_enable(struct clk *clk)
if (cpu_is_mx51())
reg &= ~MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX51;
else
- reg &= ~MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX53;
+ reg &= ~MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS;
__raw_writel(reg, MXC_CCM_CLPCR);
return 0;
@@ -991,7 +1039,7 @@ static void _clk_max_disable(struct clk *clk)
if (cpu_is_mx51())
reg |= MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX51;
else
- reg |= MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX53;
+ reg |= MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS;
__raw_writel(reg, MXC_CCM_CLPCR);
}
@@ -1078,10 +1126,18 @@ static unsigned long _clk_emi_slow_round_rate(struct clk *clk,
u32 div;
div = clk->parent->rate / rate;
+
+ /* Make sure rate is not greater than the maximum value for the clock.
+ * Also prevent a div of 0.
+ */
+ if (div == 0)
+ div++;
+ if (clk->parent->rate / div > MAX_EMI_SLOW_CLK)
+ div++;
+
if (div > 8)
div = 8;
- else if (div == 0)
- div++;
+
return clk->parent->rate / div;
}
@@ -1143,6 +1199,9 @@ static struct clk emi_intr_clk[] = {
.disable = _clk_disable_inwait,
},
{
+ /* On MX51 - this clock is name emi_garb_clk, and controls the
+ * access of ARM to GARB.
+ */
.name = "emi_intr_clk",
.id = 1,
.parent = &ahb_clk,
@@ -1311,7 +1370,7 @@ static int _clk_sdma_enable(struct clk *clk)
if (cpu_is_mx51())
reg &= ~MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX51;
else
- reg &= ~MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX53;
+ reg &= ~MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS;
__raw_writel(reg, MXC_CCM_CLPCR);
return 0;
@@ -1327,7 +1386,7 @@ static void _clk_sdma_disable(struct clk *clk)
if (cpu_is_mx51())
reg |= MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX51;
else
- reg |= MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX53;
+ reg |= MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS;
__raw_writel(reg, MXC_CCM_CLPCR);
}
@@ -1357,7 +1416,10 @@ static int _clk_ipu_enable(struct clk *clk)
_clk_enable(clk);
/* Handshake with IPU when certain clock rates are changed. */
reg = __raw_readl(MXC_CCM_CCDR);
- reg &= ~MXC_CCM_CCDR_IPU_HS_MASK;
+ if (cpu_is_mx51())
+ reg &= ~MXC_CCM_CCDR_IPU_HS_MASK;
+ else
+ reg &= ~MXC_CCM_CCDR_IPU_HS_MX53_MASK;
__raw_writel(reg, MXC_CCM_CCDR);
/* Handshake with IPU when LPM is entered as its enabled. */
@@ -1445,6 +1507,8 @@ static int _clk_ipu_di_set_parent(struct clk *clk, struct clk *parent)
reg |= 3 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id);
} else if ((parent == &tve_clk) && (clk->id == 1))
reg |= 3 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id);
+ else if ((parent == &ldb_di_clk[clk->id]) && cpu_is_mx53())
+ reg |= 5 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id);
else /* Assume any other clock is external clock pin */
reg |= 4 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id);
__raw_writel(reg, MXC_CCM_CSCMR2);
@@ -1498,7 +1562,10 @@ static int _clk_ipu_di_set_rate(struct clk *clk, unsigned long rate)
__raw_writel(reg, MXC_CCM_CDCDR);
} else if ((clk->parent == &tve_clk) && (clk->id == 1))
clk->rate = rate; /*the rate decided by tve hw actually*/
- else
+ else if ((clk->parent == &ldb_di_clk[clk->id]) && cpu_is_mx53()) {
+ clk->rate = clk->parent->rate;
+ return 0;
+ } else
return -EINVAL;
clk->rate = rate;
@@ -1511,12 +1578,16 @@ static unsigned long _clk_ipu_di_round_rate(struct clk *clk,
{
u32 div;
- div = clk->parent->rate / rate;
- if (div > 8)
- div = 8;
- else if (div == 0)
- div++;
- return clk->parent->rate / div;
+ if ((clk->parent == &ldb_di_clk[clk->id]) && cpu_is_mx53())
+ return clk->parent->rate;
+ else {
+ div = clk->parent->rate / rate;
+ if (div > 8)
+ div = 8;
+ else if (div == 0)
+ div++;
+ return clk->parent->rate / div;
+ }
}
static struct clk ipu_di_clk[] = {
@@ -1550,6 +1621,128 @@ static struct clk ipu_di_clk[] = {
},
};
+static int _clk_ldb_di_set_parent(struct clk *clk, struct clk *parent)
+{
+ u32 reg;
+
+ reg = __raw_readl(MXC_CCM_CSCMR2);
+
+ if ((parent == &pll3_sw_clk)) {
+ if (clk->id == 0)
+ reg &= ~(MXC_CCM_CSCMR2_LDB_DI0_CLK_SEL);
+ else
+ reg &= ~(MXC_CCM_CSCMR2_LDB_DI1_CLK_SEL);
+ } else if ((parent == &pll4_sw_clk)) {
+ if (clk->id == 0)
+ reg |= MXC_CCM_CSCMR2_LDB_DI0_CLK_SEL;
+ else
+ reg |= MXC_CCM_CSCMR2_LDB_DI1_CLK_SEL;
+ } else {
+ BUG();
+ }
+
+ __raw_writel(reg, MXC_CCM_CSCMR2);
+ return 0;
+}
+
+static void _clk_ldb_di_recalc(struct clk *clk)
+{
+ u32 div;
+
+ if (clk->id == 0)
+ div = __raw_readl(MXC_CCM_CSCMR2) &
+ MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV;
+ else
+ div = __raw_readl(MXC_CCM_CSCMR2) &
+ MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV;
+
+ if (div)
+ clk->rate = clk->parent->rate / 7;
+ else
+ clk->rate = 2 * clk->parent->rate / 7;
+}
+
+static unsigned long _clk_ldb_di_round_rate(struct clk *clk,
+ unsigned long rate)
+{
+ if (rate * 7 <= clk->parent->rate)
+ return clk->parent->rate / 7;
+ else
+ return 2 * clk->parent->rate / 7;
+}
+
+static int _clk_ldb_di_set_rate(struct clk *clk, unsigned long rate)
+{
+ u32 reg, div = 0;
+
+ if (rate * 7 <= clk->parent->rate) {
+ div = 7;
+ rate = clk->parent->rate / 7;
+ } else
+ rate = 2 * clk->parent->rate / 7;
+
+ reg = __raw_readl(MXC_CCM_CSCMR2);
+ if (div == 7)
+ reg |= (clk->id ? MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV :
+ MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV);
+ else
+ reg &= ~(clk->id ? MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV :
+ MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV);
+ __raw_writel(reg, MXC_CCM_CSCMR2);
+
+ clk->rate = rate;
+ return 0;
+}
+
+static int _clk_ldb_di_enable(struct clk *clk)
+{
+ _clk_enable(clk);
+ ipu_di_clk[clk->id].set_parent(&ipu_di_clk[clk->id], clk);
+ ipu_di_clk[clk->id].parent = clk;
+ ipu_di_clk[clk->id].rate = clk->rate;
+ ipu_di_clk[clk->id].enable(&ipu_di_clk[clk->id]);
+ ipu_di_clk[clk->id].usecount++;
+ return 0;
+}
+
+static void _clk_ldb_di_disable(struct clk *clk)
+{
+ _clk_disable(clk);
+ ipu_di_clk[clk->id].disable(&ipu_di_clk[clk->id]);
+ ipu_di_clk[clk->id].usecount--;
+}
+
+static struct clk ldb_di_clk[] = {
+ {
+ .name = "ldb_di0_clk",
+ .id = 0,
+ .parent = &pll4_sw_clk,
+ .enable_reg = MXC_CCM_CCGR6,
+ .enable_shift = MXC_CCM_CCGR6_CG14_OFFSET,
+ .recalc = _clk_ldb_di_recalc,
+ .set_parent = _clk_ldb_di_set_parent,
+ .round_rate = _clk_ldb_di_round_rate,
+ .set_rate = _clk_ldb_di_set_rate,
+ .enable = _clk_ldb_di_enable,
+ .disable = _clk_ldb_di_disable,
+ .flags = RATE_PROPAGATES | AHB_MED_SET_POINT,
+ },
+ {
+ .name = "ldb_di1_clk",
+ .id = 1,
+ .parent = &pll4_sw_clk,
+ .enable_reg = MXC_CCM_CCGR6,
+ .enable_shift = MXC_CCM_CCGR6_CG15_OFFSET,
+ .recalc = _clk_ldb_di_recalc,
+ .set_parent = _clk_ldb_di_set_parent,
+ .round_rate = _clk_ldb_di_round_rate,
+ .set_rate = _clk_ldb_di_set_rate,
+ .enable = _clk_ldb_di_enable,
+ .disable = _clk_ldb_di_disable,
+ .flags = RATE_PROPAGATES | AHB_MED_SET_POINT,
+ },
+};
+
static int _clk_csi0_set_parent(struct clk *clk, struct clk *parent)
{
u32 reg, mux;
@@ -2060,28 +2253,6 @@ static struct clk uart5_clk[] = {
},
};
-static struct clk esai_clk[] = {
- {
- .name = "esai_clk",
- .id = 2,
- .parent = &pll3_sw_clk,
- .secondary = &esai_clk[1],
- .enable_reg = MXC_CCM_CCGR6,
- .enable_shift = MXC_CCM_CCGR6_CG9_OFFSET,
- .enable = _clk_enable,
- .disable = _clk_disable,
- },
- {
- .name = "esai_ipg_clk",
- .id = 2,
- .parent = &pll3_sw_clk,
- .enable_reg = MXC_CCM_CCGR6,
- .enable_shift = MXC_CCM_CCGR6_CG8_OFFSET,
- .enable = _clk_enable,
- .disable = _clk_disable,
- },
-};
-
static struct clk gpt_clk[] = {
{
.name = "gpt_clk",
@@ -2311,23 +2482,15 @@ static struct clk cspi2_clk[] = {
},
};
-static struct clk cspi3_clk[] = {
- {
- .name = "cspi_clk",
- .id = 2,
- .parent = &cspi_main_clk,
- .enable_reg = MXC_CCM_CCGR4,
- .enable_shift = MXC_CCM_CCGR4_CG13_OFFSET,
- .enable = _clk_enable,
- .disable = _clk_disable,
- .secondary = &cspi3_clk[1],
- },
- {
- .name = "cspi_ipg_clk",
- .id = 2,
- .parent = &ipg_clk,
- .secondary = &aips_tz2_clk,
- },
+static struct clk cspi3_clk = {
+ .name = "cspi_ipg_clk",
+ .id = 2,
+ .parent = &ipg_clk,
+ .enable_reg = MXC_CCM_CCGR4,
+ .enable_shift = MXC_CCM_CCGR4_CG13_OFFSET,
+ .enable = _clk_enable,
+ .disable = _clk_disable,
+ .secondary = &aips_tz2_clk,
};
static int _clk_ssi_lp_apm_set_parent(struct clk *clk, struct clk *parent)
@@ -2612,6 +2775,83 @@ static struct clk ssi_ext2_clk = {
.disable = _clk_disable,
};
+static int _clk_esai_set_parent(struct clk *clk, struct clk *parent)
+{
+ u32 reg, mux;
+
+ reg = __raw_readl(MXC_CCM_CSCMR2);
+ if (parent == &pll1_sw_clk || parent == &pll2_sw_clk ||
+ parent == &pll3_sw_clk) {
+ mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk,
+ NULL);
+ reg &= ~MXC_CCM_CSCMR2_ESAI_PRE_SEL_MASK;
+ reg |= mux << MXC_CCM_CSCMR2_ESAI_PRE_SEL_OFFSET;
+ reg &= ~MXC_CCM_CSCMR2_ESAI_POST_SEL_MASK;
+ reg |= 0 << MXC_CCM_CSCMR2_ESAI_POST_SEL_OFFSET;
+ /* divider setting */
+ } else {
+ mux = _get_mux(parent, &ssi1_clk[0], &ssi2_clk[0], &ckih_clk,
+ &ckih2_clk);
+ reg &= ~MXC_CCM_CSCMR2_ESAI_POST_SEL_MASK;
+ reg |= (mux + 1) << MXC_CCM_CSCMR2_ESAI_POST_SEL_OFFSET;
+ /* divider setting */
+ }
+
+ __raw_writel(reg, MXC_CCM_CSCMR2);
+
+ /* set podf = 0 */
+ reg = __raw_readl(MXC_CCM_CS1CDR);
+ reg &= ~MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK;
+ __raw_writel(reg, MXC_CCM_CS1CDR);
+
+ return 0;
+}
+
+static void _clk_esai_recalc(struct clk *clk)
+{
+ u32 reg, pred, podf;
+
+ reg = __raw_readl(MXC_CCM_CS1CDR);
+ if (clk->parent == &pll1_sw_clk || clk->parent == &pll2_sw_clk ||
+ clk->parent == &pll3_sw_clk) {
+ pred = ((reg & MXC_CCM_CS1CDR_ESAI_CLK_PRED_MASK) >>
+ MXC_CCM_CS1CDR_ESAI_CLK_PRED_OFFSET) + 1;
+ podf = ((reg & MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK) >>
+ MXC_CCM_CS1CDR_ESAI_CLK_PODF_OFFSET) + 1;
+
+ clk->rate = clk->parent->rate / (pred * podf);
+ } else {
+ podf = ((reg & MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK) >>
+ MXC_CCM_CS1CDR_ESAI_CLK_PODF_OFFSET) + 1;
+
+ clk->rate = clk->parent->rate / podf;
+ }
+}
+
+static struct clk esai_clk[] = {
+ {
+ .name = "esai_clk",
+ .id = 0,
+ .parent = &pll3_sw_clk,
+ .set_parent = _clk_esai_set_parent,
+ .recalc = _clk_esai_recalc,
+ .secondary = &esai_clk[1],
+ .enable_reg = MXC_CCM_CCGR6,
+ .enable_shift = MXC_CCM_CCGR6_CG9_OFFSET,
+ .enable = _clk_enable,
+ .disable = _clk_disable,
+ },
+ {
+ .name = "esai_ipg_clk",
+ .id = 0,
+ .parent = &ipg_clk,
+ .enable_reg = MXC_CCM_CCGR6,
+ .enable_shift = MXC_CCM_CCGR6_CG8_OFFSET,
+ .enable = _clk_enable,
+ .disable = _clk_disable,
+ },
+};
+
static struct clk iim_clk = {
.name = "iim_clk",
.parent = &ipg_clk,
@@ -3135,51 +3375,63 @@ static struct clk ieee_1588_clk = {
.disable = _clk_disable,
};
-static struct clk mlb_clk = {
+static struct clk mlb_clk[] = {
+ {
.name = "mlb_clk",
.parent = &ipg_clk,
.enable = _clk_enable,
.enable_reg = MXC_CCM_CCGR7,
.enable_shift = MXC_CCM_CCGR7_CG2_OFFSET,
.disable = _clk_disable,
+ .secondary = &mlb_clk[1],
+ },
+ {
+ .name = "mlb_mem_clk",
+ .parent = &emi_fast_clk,
+ .secondary = &emi_intr_clk[1],
+ },
};
static struct clk can1_clk[] = {
{
- .name = "can1_clk",
- .parent = &pll3_sw_clk,
- .secondary = &can1_clk[1],
+ .name = "can_clk",
+ .id = 0,
+ .parent = &ipg_clk,
.enable = _clk_enable,
+ .secondary = &can1_clk[1],
.enable_reg = MXC_CCM_CCGR6,
- .enable_shift = MXC_CCM_CCGR6_CG11_OFFSET,
+ .enable_shift = MXC_CCM_CCGR6_CG10_OFFSET,
.disable = _clk_disable,
},
{
- .name = "can1_ipg_clk",
- .parent = &ipg_clk,
+ .name = "can_cpi_clk",
+ .id = 0,
+ .parent = &lp_apm_clk,
.enable = _clk_enable,
.enable_reg = MXC_CCM_CCGR6,
- .enable_shift = MXC_CCM_CCGR6_CG10_OFFSET,
+ .enable_shift = MXC_CCM_CCGR6_CG11_OFFSET,
.disable = _clk_disable,
},
};
static struct clk can2_clk[] = {
{
- .name = "can2_clk",
- .parent = &pll3_sw_clk,
- .secondary = &can2_clk[1],
+ .name = "can_clk",
+ .id = 1,
+ .parent = &ipg_clk,
.enable = _clk_enable,
+ .secondary = &can2_clk[1],
.enable_reg = MXC_CCM_CCGR4,
- .enable_shift = MXC_CCM_CCGR4_CG4_OFFSET,
+ .enable_shift = MXC_CCM_CCGR4_CG3_OFFSET,
.disable = _clk_disable,
},
{
- .name = "can2_ipg_clk",
- .parent = &ipg_clk,
+ .name = "can_cpi_clk",
+ .id = 1,
+ .parent = &lp_apm_clk,
.enable = _clk_enable,
.enable_reg = MXC_CCM_CCGR4,
- .enable_shift = MXC_CCM_CCGR4_CG3_OFFSET,
+ .enable_shift = MXC_CCM_CCGR4_CG4_OFFSET,
.disable = _clk_disable,
},
};
@@ -3680,7 +3932,6 @@ static struct clk pgc_clk = {
};
/*usb OTG clock */
-
static struct clk usb_clk = {
.name = "usb_clk",
.rate = 60000000,
@@ -3716,7 +3967,8 @@ static struct clk ata_clk = {
};
static struct clk owire_clk = {
- .name = "owire_clk",
+ /* 1w driver come from upstream and use owire as clock name*/
+ .name = "owire",
.parent = &ipg_perclk,
.enable = _clk_enable,
.enable_reg = MXC_CCM_CCGR2,
@@ -3796,16 +4048,6 @@ static int _clk_gpu3d_set_parent(struct clk *clk, struct clk *parent)
return 0;
}
-static struct clk gpu3d_clk = {
- .name = "gpu3d_clk",
- .parent = &axi_a_clk,
- .set_parent = _clk_gpu3d_set_parent,
- .enable = _clk_enable,
- .enable_reg = MXC_CCM_CCGR5,
- .enable_shift = MXC_CCM_CCGR5_CG1_OFFSET,
- .disable = _clk_disable,
- .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
-};
static struct clk garb_clk = {
.name = "garb_clk",
@@ -3816,13 +4058,16 @@ static struct clk garb_clk = {
.disable = _clk_disable,
};
-static struct clk emi_garb_clk = {
- .name = "emi_garb_clk",
+static struct clk gpu3d_clk = {
+ .name = "gpu3d_clk",
.parent = &axi_a_clk,
+ .set_parent = _clk_gpu3d_set_parent,
.enable = _clk_enable,
- .enable_reg = MXC_CCM_CCGR6,
- .enable_shift = MXC_CCM_CCGR6_CG4_OFFSET,
- .disable = _clk_disable_inwait,
+ .enable_reg = MXC_CCM_CCGR5,
+ .enable_shift = MXC_CCM_CCGR5_CG1_OFFSET,
+ .disable = _clk_disable,
+ .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+ .secondary = &garb_clk,
};
static int _clk_gpu2d_set_parent(struct clk *clk, struct clk *parent)
@@ -4008,8 +4253,7 @@ static struct clk *mxc_clks[] = {
&cspi1_clk[1],
&cspi2_clk[0],
&cspi2_clk[1],
- &cspi3_clk[0],
- &cspi3_clk[1],
+ &cspi3_clk,
&ssi_lp_apm_clk,
&ssi1_clk[0],
&ssi1_clk[1],
@@ -4043,6 +4287,7 @@ static struct clk *mxc_clks[] = {
&emi_enfc_clk,
&emi_fast_clk,
&emi_intr_clk[0],
+ &emi_intr_clk[1],
&spdif_xtal_clk,
&spdif0_clk[0],
&spdif0_clk[1],
@@ -4111,9 +4356,6 @@ static void clk_tree_init(void)
pll4_sw_clk.parent = &osc_clk;
}
- if (cpu_is_mx53())
- tve_clk.parent = &pll4_sw_clk;
-
/* set emi_slow_clk parent */
emi_slow_clk.parent = &main_bus_clk;
reg = __raw_readl(MXC_CCM_CBCDR);
@@ -4191,6 +4433,7 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long
esdhc2_clk[0].recalc = _clk_esdhc2_recalc;
esdhc2_clk[0].set_rate = _clk_esdhc2_set_rate;
+ emi_intr_clk[1].name = "emi_garb_clk";
clk_tree_init();
for (clkp = mxc_clks; clkp < mxc_clks + ARRAY_SIZE(mxc_clks); clkp++)
@@ -4209,7 +4452,9 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long
clk_register(&spdif1_clk[0]);
clk_register(&spdif1_clk[1]);
clk_register(&ddr_hf_clk);
- clk_register(&emi_garb_clk);
+
+ max_axi_a_clk = MAX_AXI_A_CLK_MX51;
+ max_axi_b_clk = MAX_AXI_B_CLK_MX51;
/* set DDR clock parent */
reg = 0;
@@ -4261,8 +4506,10 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long
propagate_rate(&pll1_sw_clk);
propagate_rate(&pll2_sw_clk);
+#ifndef CONFIG_LATE_CPU_CLK_ENABLE
+ /* See comment below where cpu_clk is enabled for further information */
clk_enable(&cpu_clk);
-
+#endif
/* Set SDHC parents to be PLL2 */
clk_set_parent(&esdhc1_clk[0], &pll2_sw_clk);
clk_set_parent(&esdhc2_clk[0], &pll2_sw_clk);
@@ -4396,13 +4643,6 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long
if (i > cpu_wp_nr)
BUG();
- /*Allow for automatic gating of the EMI internal clock.
- * If this is done, emi_intr CCGR bits should be set to 11.
- */
- reg = __raw_readl((IO_ADDRESS(M4IF_BASE_ADDR) + 0x8c));
- reg &= ~0x1;
- __raw_writel(reg, (IO_ADDRESS(M4IF_BASE_ADDR) + 0x8c));
-
clk_set_parent(&arm_axi_clk, &axi_a_clk);
clk_set_parent(&ipu_clk[0], &axi_b_clk);
@@ -4418,8 +4658,8 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long
(0 << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET);
__raw_writel(reg, MXC_CCM_CSCDR1);
} else {
- /* Move UART to run from PLL1 */
- clk_set_parent(&uart_main_clk, &pll1_sw_clk);
+ /* Move UART to run from PLL2 */
+ clk_set_parent(&uart_main_clk, &pll2_sw_clk);
/* Set the UART dividers to divide,
* so the UART_CLK is 66.5MHz.
@@ -4427,7 +4667,7 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long
reg = __raw_readl(MXC_CCM_CSCDR1);
reg &= ~MXC_CCM_CSCDR1_UART_CLK_PODF_MASK;
reg &= ~MXC_CCM_CSCDR1_UART_CLK_PRED_MASK;
- reg |= (5 << MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) |
+ reg |= (4 << MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) |
(1 << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET);
__raw_writel(reg, MXC_CCM_CSCDR1);
}
@@ -4446,6 +4686,15 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long
base = ioremap(GPT1_BASE_ADDR, SZ_4K);
mxc_timer_init(&gpt_clk[0], base, MXC_INT_GPT);
+#ifdef CONFIG_LATE_CPU_CLK_ENABLE
+ /**
+ * Late enable of the cpu clock. This is causing a random crash at boot
+ * time on the ConnectCore Wi-i.MX51. Enabling the cpu clock here seems
+ * to work around the problem. Must be in order to better understand the
+ * reason of the problem and the real solution to the problem.
+ */
+ clk_enable(&cpu_clk);
+#endif
return 0;
}
@@ -4493,15 +4742,15 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long
1 << MXC_CCM_CCGR5_CG6_OFFSET |
3 << MXC_CCM_CCGR5_CG7_OFFSET |
1 << MXC_CCM_CCGR5_CG8_OFFSET |
- 3 << MXC_CCM_CCGR5_CG9_OFFSET |
+ 1 << MXC_CCM_CCGR5_CG9_OFFSET |
1 << MXC_CCM_CCGR5_CG10_OFFSET |
3 << MXC_CCM_CCGR5_CG11_OFFSET, MXC_CCM_CCGR5);
- __raw_writel(3 << MXC_CCM_CCGR6_CG0_OFFSET |
+ __raw_writel(1 << MXC_CCM_CCGR6_CG0_OFFSET |
3 << MXC_CCM_CCGR6_CG1_OFFSET |
- 3 << MXC_CCM_CCGR6_CG4_OFFSET |
- 3 << MXC_CCM_CCGR6_CG8_OFFSET |
- 3 << MXC_CCM_CCGR6_CG9_OFFSET |
+ 1 << MXC_CCM_CCGR6_CG4_OFFSET |
+ 1 << MXC_CCM_CCGR6_CG8_OFFSET |
+ 1 << MXC_CCM_CCGR6_CG9_OFFSET |
3 << MXC_CCM_CCGR6_CG12_OFFSET |
3 << MXC_CCM_CCGR6_CG13_OFFSET , MXC_CCM_CCGR6);
@@ -4544,7 +4793,6 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long
clk_register(*clkp);
clk_register(&pll4_sw_clk);
- clk_register(&emi_intr_clk[1]);
clk_register(&uart4_clk[0]);
clk_register(&uart4_clk[1]);
clk_register(&uart5_clk[0]);
@@ -4554,7 +4802,21 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long
clk_register(&ocram_clk);
clk_register(&sata_clk);
clk_register(&ieee_1588_clk);
- clk_register(&mlb_clk);
+ clk_register(&mlb_clk[0]);
+ clk_register(&can1_clk[0]);
+ clk_register(&can2_clk[0]);
+ clk_register(&ldb_di_clk[0]);
+ clk_register(&ldb_di_clk[1]);
+ /* OSC of 22.5792M or 24.576M for ESAI */
+ clk_register(&esai_clk[0]);
+ clk_set_parent(&esai_clk[0], &ckih_clk);
+ clk_register(&esai_clk[1]);
+
+ ldb_di_clk[0].parent = ldb_di_clk[1].parent =
+ tve_clk.parent = &pll4_sw_clk;
+
+ max_axi_a_clk = MAX_AXI_A_CLK_MX53;
+ max_axi_b_clk = MAX_AXI_B_CLK_MX53;
/* set DDR clock parent */
reg = __raw_readl(MXC_CCM_CBCMR) &
@@ -4575,6 +4837,8 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long
clk_set_parent(&esdhc2_clk[0], &esdhc1_clk[0]);
clk_set_parent(&esdhc3_clk[0], &pll2_sw_clk);
+ clk_set_parent(&ipu_di_clk[0], &pll4_sw_clk);
+
#if 0
/*Setup the LPM bypass bits */
reg = __raw_readl(MXC_CCM_CLPCR);
@@ -4585,13 +4849,6 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long
__raw_writel(reg, MXC_CCM_CLPCR);
#endif
- /* Disable the handshake with HSC block as its not
- * initialised right now.
- */
- reg = __raw_readl(MXC_CCM_CCDR);
- reg |= MXC_CCM_CCDR_EMI_HS_MASK;
- __raw_writel(reg, MXC_CCM_CCDR);
-
/* This will propagate to all children and init all the clock rates */
propagate_rate(&osc_clk);
propagate_rate(&ckih_clk);
@@ -4605,14 +4862,15 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long
clk_enable(&main_bus_clk);
+ /* Set AXI_B_CLK to be 200MHz */
+ clk_set_rate(&axi_b_clk, 200000000);
+
/* Initialise the parents to be axi_b, parents are set to
* axi_a when the clocks are enabled.
*/
clk_set_parent(&vpu_clk[0], &axi_b_clk);
clk_set_parent(&vpu_clk[1], &axi_b_clk);
- clk_set_parent(&gpu3d_clk, &axi_a_clk);
- clk_set_parent(&gpu2d_clk, &axi_a_clk);
/* move cspi to 24MHz */
clk_set_parent(&cspi_main_clk, &lp_apm_clk);
@@ -4797,27 +5055,27 @@ static int cpu_clk_set_wp(int wp)
__raw_writel(reg, MXC_CCM_CCSR);
/* Stop the PLL */
- reg = __raw_readl(MXC_DPLL1_BASE + MXC_PLL_DP_CTL);
+ reg = __raw_readl(pll1_base + MXC_PLL_DP_CTL);
reg &= ~MXC_PLL_DP_CTL_UPEN;
- __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_CTL);
+ __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL);
/* PDF and MFI */
reg = p->pdf | p->mfi << MXC_PLL_DP_OP_MFI_OFFSET;
- __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_OP);
+ __raw_writel(reg, pll1_base + MXC_PLL_DP_OP);
/* MFD */
- __raw_writel(p->mfd, MXC_DPLL1_BASE + MXC_PLL_DP_MFD);
+ __raw_writel(p->mfd, pll1_base + MXC_PLL_DP_MFD);
/* MFI */
- __raw_writel(p->mfn, MXC_DPLL1_BASE + MXC_PLL_DP_MFN);
+ __raw_writel(p->mfn, pll1_base + MXC_PLL_DP_MFN);
- reg = __raw_readl(MXC_DPLL1_BASE + MXC_PLL_DP_CTL);
+ reg = __raw_readl(pll1_base + MXC_PLL_DP_CTL);
reg |= MXC_PLL_DP_CTL_UPEN;
/* Set the UPEN bits */
- __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_CTL);
+ __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL);
/* Forcefully restart the PLL */
reg |= MXC_PLL_DP_CTL_RST;
- __raw_writel(reg, MXC_DPLL1_BASE + MXC_PLL_DP_CTL);
+ __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL);
/* Wait for the PLL to lock */
getnstimeofday(&nstimeofday);
@@ -4825,7 +5083,7 @@ static int cpu_clk_set_wp(int wp)
getnstimeofday(&curtime);
if ((curtime.tv_nsec - nstimeofday.tv_nsec) > SPIN_DELAY)
panic("pll1 relock failed\n");
- stat = __raw_readl(MXC_DPLL1_BASE + MXC_PLL_DP_CTL) &
+ stat = __raw_readl(pll1_base + MXC_PLL_DP_CTL) &
MXC_PLL_DP_CTL_LRF;
} while (!stat);
diff --git a/arch/arm/mach-mx5/cpu.c b/arch/arm/mach-mx5/cpu.c
index 692d258a4a0c..44440569f041 100644
--- a/arch/arm/mach-mx5/cpu.c
+++ b/arch/arm/mach-mx5/cpu.c
@@ -19,6 +19,7 @@
* @ingroup MSL_MX51
*/
+#include <linux/proc_fs.h>
#include <linux/types.h>
#include <linux/err.h>
#include <linux/kernel.h>
@@ -28,10 +29,29 @@
#include <linux/clk.h>
#include <mach/common.h>
#include <mach/hardware.h>
-#include "crm_regs.h"
+#include <asm/mach/map.h>
+
+#define CORTEXA8_PLAT_AMC 0x18
+#define SRPG_NEON_PUPSCR 0x284
+#define SRPG_NEON_PDNSCR 0x288
+#define SRPG_ARM_PUPSCR 0x2A4
+#define SRPG_ARM_PDNSCR 0x2A8
+#define SRPG_EMPGC0_PUPSCR 0x2E4
+#define SRPG_EMPGC0_PDNSCR 0x2E8
+#define SRPG_EMPGC1_PUPSCR 0x304
+#define SRPG_EMPGC1_PDNSCR 0x308
void __iomem *arm_plat_base;
void __iomem *gpc_base;
+void __iomem *ccm_base;
+void __iomem *databahn_base;
+void *wait_in_iram_base;
+void (*wait_in_iram)(void *ccm_addr, void *databahn_addr);
+
+extern void mx50_wait(u32 ccm_base, u32 databahn_addr);
+
+struct cpu_wp *(*get_cpu_wp)(int *wp);
+void (*set_num_cpu_wp)(int num);
static void __init mipi_hsc_disable(void)
{
@@ -54,7 +74,8 @@ static void __init mipi_hsc_disable(void)
if (cpu_is_mx51_rev(CHIP_REV_2_0) > 0) {
temp = __raw_readl(reg_hsc_mxt_conf);
- __raw_writel(temp | 0x10000, reg_hsc_mxt_conf);
+ __raw_writel(0xf003008b, reg_hsc_mxt_conf);
+ /* Previous value of reg_hsc_mxt_conf was 0xf00100ff */
}
clk_disable(clk);
@@ -102,6 +123,7 @@ static int __init post_cpu_init(void)
{
void __iomem *base;
unsigned int reg;
+ struct clk *gpcclk = clk_get(NULL, "gpc_dvfs_clk");
int iram_size = IRAM_SIZE;
if (cpu_is_mx51()) {
@@ -116,11 +138,30 @@ static int __init post_cpu_init(void)
}
gpc_base = ioremap(MX53_BASE_ADDR(GPC_BASE_ADDR), SZ_4K);
+ ccm_base = ioremap(MX53_BASE_ADDR(CCM_BASE_ADDR), SZ_4K);
+
+ clk_enable(gpcclk);
+
+ /* Setup the number of clock cycles to wait for SRPG
+ * power up and power down requests.
+ */
+ __raw_writel(0x010F0201, gpc_base + SRPG_ARM_PUPSCR);
+ __raw_writel(0x010F0201, gpc_base + SRPG_NEON_PUPSCR);
+ __raw_writel(0x00000008, gpc_base + SRPG_EMPGC0_PUPSCR);
+ __raw_writel(0x00000008, gpc_base + SRPG_EMPGC1_PUPSCR);
+
+ __raw_writel(0x01010101, gpc_base + SRPG_ARM_PDNSCR);
+ __raw_writel(0x01010101, gpc_base + SRPG_NEON_PDNSCR);
+ __raw_writel(0x00000018, gpc_base + SRPG_EMPGC0_PDNSCR);
+ __raw_writel(0x00000018, gpc_base + SRPG_EMPGC1_PDNSCR);
+
+ clk_disable(gpcclk);
+ clk_put(gpcclk);
/* Set ALP bits to 000. Set ALP_EN bit in Arm Memory Controller reg. */
arm_plat_base = ioremap(MX53_BASE_ADDR(ARM_BASE_ADDR), SZ_4K);
reg = 0x8;
- __raw_writel(reg, MXC_CORTEXA8_PLAT_AMC);
+ __raw_writel(reg, arm_plat_base + CORTEXA8_PLAT_AMC);
base = ioremap(MX53_BASE_ADDR(AIPS1_BASE_ADDR), SZ_4K);
__raw_writel(0x0, base + 0x40);
@@ -140,15 +181,53 @@ static int __init post_cpu_init(void)
__raw_writel(reg, base + 0x50);
iounmap(base);
- /*Allow for automatic gating of the EMI internal clock.
- * If this is done, emi_intr CCGR bits should be set to 11.
- */
- base = ioremap(MX53_BASE_ADDR(M4IF_BASE_ADDR), SZ_4K);
- reg = __raw_readl(base + 0x8c);
- reg &= ~0x1;
- __raw_writel(reg, base + 0x8c);
- iounmap(base);
+ if (cpu_is_mx51() || cpu_is_mx53()) {
+ /*Allow for automatic gating of the EMI internal clock.
+ * If this is done, emi_intr CCGR bits should be set to 11.
+ */
+ base = ioremap(MX53_BASE_ADDR(M4IF_BASE_ADDR), SZ_4K);
+ reg = __raw_readl(base + 0x8c);
+ reg &= ~0x1;
+ __raw_writel(reg, base + 0x8c);
+ iounmap(base);
+ }
+ databahn_base = ioremap(MX50_DATABAHN_BASE_ADDR, SZ_16K);
+
+ if (cpu_is_mx50()) {
+ struct clk *ddr_clk = clk_get(NULL, "ddr_clk");
+ unsigned long iram_paddr;
+
+ iram_alloc(SZ_4K, &iram_paddr);
+ /* Need to remap the area here since we want the memory region
+ to be executable. */
+ wait_in_iram_base = __arm_ioremap(iram_paddr,
+ SZ_4K, MT_HIGH_VECTORS);
+ memcpy(wait_in_iram_base, mx50_wait, SZ_4K);
+ wait_in_iram = (void *)wait_in_iram_base;
+
+ clk_enable(ddr_clk);
+
+ /* Set the DDR to enter automatic self-refresh. */
+ /* Set the DDR to automatically enter lower power mode 4. */
+ reg = __raw_readl(databahn_base + DATABAHN_CTL_REG22);
+ reg &= ~LOWPOWER_AUTOENABLE_MASK;
+ reg |= 1 << 1;
+ __raw_writel(reg, databahn_base + DATABAHN_CTL_REG22);
+
+ /* set the counter for entering mode 4. */
+ reg = __raw_readl(databahn_base + DATABAHN_CTL_REG21);
+ reg &= ~LOWPOWER_EXTERNAL_CNT_MASK;
+ reg = 128 << LOWPOWER_EXTERNAL_CNT_OFFSET;
+ __raw_writel(reg, databahn_base + DATABAHN_CTL_REG21);
+
+ /* Enable low power mode 4 */
+ reg = __raw_readl(databahn_base + DATABAHN_CTL_REG20);
+ reg &= ~LOWPOWER_CONTROL_MASK;
+ reg |= 1 << 1;
+ __raw_writel(reg, databahn_base + DATABAHN_CTL_REG20);
+ clk_disable(ddr_clk);
+ }
return 0;
}
diff --git a/arch/arm/mach-mx5/crm_regs.h b/arch/arm/mach-mx5/crm_regs.h
index e53f55d258eb..b2660a34c0e9 100644
--- a/arch/arm/mach-mx5/crm_regs.h
+++ b/arch/arm/mach-mx5/crm_regs.h
@@ -13,17 +13,7 @@
#ifndef __ARCH_ARM_MACH_MX51_CRM_REGS_H__
#define __ARCH_ARM_MACH_MX51_CRM_REGS_H__
-extern void __iomem *ccm_base;
-extern void __iomem *pll1_base;
-extern void __iomem *pll2_base;
-extern void __iomem *pll3_base;
-extern void __iomem *pll4_base;
-
#define MXC_CCM_BASE (IO_ADDRESS(CCM_BASE_ADDR))
-#define MXC_DPLL1_BASE (pll1_base)
-#define MXC_DPLL2_BASE (pll2_base)
-#define MXC_DPLL3_BASE (pll3_base)
-#define MXC_DPLL4_BASE (pll4_base)
/* PLL Register Offsets */
#define MXC_PLL_DP_CTL 0x00
@@ -80,6 +70,56 @@ extern void __iomem *pll4_base;
#define MXC_PLL_DP_DESTAT_TOG_SEL (1 << 31)
#define MXC_PLL_DP_DESTAT_MFN 0x07FFFFFF
+/* Register addresses of apll and pfd*/
+#define MXC_ANADIG_FRAC0 0x10
+#define MXC_ANADIG_FRAC0_SET 0x14
+#define MXC_ANADIG_FRAC0_CLR 0x18
+#define MXC_ANADIG_FRAC1 0x20
+#define MXC_ANADIG_FRAC1_SET 0x24
+#define MXC_ANADIG_FRAC1_CLR 0x28
+#define MXC_ANADIG_MISC 0x60
+#define MXC_ANADIG_MISC_SET 0x64
+#define MXC_ANADIG_MISC_CLR 0x68
+#define MXC_ANADIG_PLLCTRL 0x70
+#define MXC_ANADIG_PLLCTRL_SET 0x74
+#define MXC_ANADIG_PLLCTRL_CLR 0x78
+
+/* apll and pfd Register Bit definitions */
+
+#define MXC_ANADIG_PFD3_CLKGATE (1 << 31)
+#define MXC_ANADIG_PFD3_STABLE (1 << 30)
+#define MXC_ANADIG_PFD3_FRAC_OFFSET 24
+#define MXC_ANADIG_PFD_FRAC_MASK 0x3F
+#define MXC_ANADIG_PFD2_CLKGATE (1 << 23)
+#define MXC_ANADIG_PFD2_STABLE (1 << 22)
+#define MXC_ANADIG_PFD2_FRAC_OFFSET 16
+#define MXC_ANADIG_PFD1_CLKGATE (1 << 15)
+#define MXC_ANADIG_PFD1_STABLE (1 << 14)
+#define MXC_ANADIG_PFD1_FRAC_OFFSET 8
+#define MXC_ANADIG_PFD0_CLKGATE (1 << 7)
+#define MXC_ANADIG_PFD0_STABLE (1 << 6)
+#define MXC_ANADIG_PFD0_FRAC_OFFSET 0
+
+#define MXC_ANADIG_PFD7_CLKGATE (1 << 31)
+#define MXC_ANADIG_PFD7_STABLE (1 << 30)
+#define MXC_ANADIG_PFD7_FRAC_OFFSET 24
+#define MXC_ANADIG_PFD6_CLKGATE (1 << 23)
+#define MXC_ANADIG_PFD6_STABLE (1 << 22)
+#define MXC_ANADIG_PFD6_FRAC_OFFSET 16
+#define MXC_ANADIG_PFD5_CLKGATE (1 << 15)
+#define MXC_ANADIG_PFD5_STABLE (1 << 14)
+#define MXC_ANADIG_PFD5_FRAC_OFFSET 8
+#define MXC_ANADIG_PFD4_CLKGATE (1 << 7)
+#define MXC_ANADIG_PFD4_STABLE (1 << 6)
+#define MXC_ANADIG_PFD4_FRAC_OFFSET 0
+
+#define MXC_ANADIG_APLL_LOCK (1 << 31)
+#define MXC_ANADIG_APLL_FORCE_LOCK (1 << 30)
+#define MXC_ANADIG_PFD_DIS_OFFSET 16
+#define MXC_ANADIG_PFD_DIS_MASK 0xff
+#define MXC_ANADIG_APLL_LOCK_CNT_OFFSET 0
+#define MXC_ANADIG_APLL_LOCK_CNT_MASK 0xffff
+
/* Register addresses of CCM*/
#define MXC_CCM_CCR (MXC_CCM_BASE + 0x00)
#define MXC_CCM_CCDR (MXC_CCM_BASE + 0x04)
@@ -116,6 +156,22 @@ extern void __iomem *pll4_base;
#define MXC_CCM_CCGR6 (MXC_CCM_BASE + 0x80)
#define MXC_CCM_CCGR7 (MXC_CCM_BASE + 0x84)
#define MXC_CCM_CMEOR (MXC_CCM_BASE + 0x88)
+#define MXC_CCM_CSR2 (MXC_CCM_BASE + 0x8C)
+#define MXC_CCM_CLKSEQ_BYPASS (MXC_CCM_BASE + 0x90)
+#define MXC_CCM_CLK_SYS (MXC_CCM_BASE + 0x94)
+#define MXC_CCM_CLK_DDR (MXC_CCM_BASE + 0x98)
+#define MXC_CCM_ELCDIFPIX (MXC_CCM_BASE + 0x9C)
+#define MXC_CCM_EPDCPIX (MXC_CCM_BASE + 0xA0)
+#define MXC_CCM_DISPLAY_AXI (MXC_CCM_BASE + 0xA4)
+#define MXC_CCM_EPDC_AXI (MXC_CCM_BASE + 0xA8)
+#define MXC_CCM_GPMI (MXC_CCM_BASE + 0xAC)
+#define MXC_CCM_BCH (MXC_CCM_BASE + 0xB0)
+#define MXC_CCM_MSHC_XMSCKI (MXC_CCM_BASE + 0xB4)
+
+/* CCM Register Offsets. */
+#define MXC_CCM_CDCR_OFFSET 0x4C
+#define MXC_CCM_CACRR_OFFSET 0x10
+#define MXC_CCM_CDHIPR_OFFSET 0x48
/* Define the bits in register CCR */
#define MXC_CCM_CCR_COSC_EN (1 << 12)
@@ -149,8 +205,11 @@ extern void __iomem *pll4_base;
#define MXC_CCM_CSR_REF_EN_B (1 << 0)
/* Define the bits in register CCSR */
-#define MXC_CCM_CCSR_LP_APM_SEL (0x1 << 9)
-#define MXC_CCM_CCSR_LP_APM_SEL_MX53 (0x1 << 10)
+#define MXC_CCM_CCSR_PLL3_PFD_EN (0x1 << 13)
+#define MXC_CCM_CCSR_PLL2_PFD_EN (0x1 << 12)
+#define MXC_CCM_CCSR_PLL1_PFD_EN (0x1 << 11)
+#define MXC_CCM_CCSR_LP_APM_SEL (0x1 << 10)
+#define MXC_CCM_CCSR_LP_APM_SE_MX51L (0x1 << 9)
#define MXC_CCM_CCSR_PLL4_SW_CLK_SEL (1 << 9)
#define MXC_CCM_CCSR_STEP_SEL_OFFSET (7)
#define MXC_CCM_CCSR_STEP_SEL_MASK (0x3 << 7)
@@ -167,12 +226,17 @@ extern void __iomem *pll4_base;
#define MXC_CCM_CACRR_ARM_PODF_MASK (0x7)
/* Define the bits in register CBCDR */
+#define MX50_CCM_CBCDR_WEIM_CLK_SEL (0x1 << 27)
#define MXC_CCM_CBCDR_EMI_CLK_SEL (0x1 << 26)
#define MXC_CCM_CBCDR_PERIPH_CLK_SEL (0x1 << 25)
+#define MX50_CCM_CBCDR_PERIPH_CLK_SEL_OFFSET (25)
+#define MX50_CCM_CBCDR_PERIPH_CLK_SEL_MASK (0x3 << 25)
#define MXC_CCM_CBCDR_DDR_HF_SEL_OFFSET (30)
#define MXC_CCM_CBCDR_DDR_HF_SEL (0x1 << 30)
#define MXC_CCM_CBCDR_DDR_PODF_OFFSET (27)
-#define MXC_CCM_CBCDR_DDR_PODF_MASK (0x7 << 27)
+#define MXC_CCM_CBCDR_DDR_PODF_MASK (0x7 << 27)
+#define MX50_CCM_CBCDR_WEIM_PODF_OFFSET (22)
+#define MX50_CCM_CBCDR_WEIM_PODF_MASK (0x7 << 22)
#define MXC_CCM_CBCDR_EMI_PODF_OFFSET (22)
#define MXC_CCM_CBCDR_EMI_PODF_MASK (0x7 << 22)
#define MXC_CCM_CBCDR_AXI_B_PODF_OFFSET (19)
@@ -209,6 +273,8 @@ extern void __iomem *pll4_base;
#define MXC_CCM_CBCMR_GPU_CLK_SEL_MASK (0x3 << 4)
#define MXC_CCM_CBCMR_GPU2D_CLK_SEL_OFFSET (14)
#define MXC_CCM_CBCMR_GPU2D_CLK_SEL_MASK (0x3 << 14)
+#define MXC_CCM_CBCMR_DBG_APB_CLK_SEL_OFFSET (2)
+#define MXC_CCM_CBCMR_DBG_APB_CLK_SEL_MASK (0x3 << 2)
#define MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL (0x1 << 1)
#define MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL (0x1 << 0)
@@ -228,6 +294,12 @@ extern void __iomem *pll4_base;
#define MXC_CCM_CSCMR1_ESDHC3_CLK_SEL_MX51 (0x1 << 19)
#define MXC_CCM_CSCMR1_ESDHC2_CLK_SEL (0x1 << 19)
#define MXC_CCM_CSCMR1_ESDHC4_CLK_SEL (0x1 << 18)
+#define MX50_CCM_CSCMR1_ESDHC1_CLK_SEL_OFFSET (21)
+#define MX50_CCM_CSCMR1_ESDHC1_CLK_SEL_MASK (0x3 << 21)
+#define MX50_CCM_CSCMR1_ESDHC2_CLK_SEL (0x1 << 20)
+#define MX50_CCM_CSCMR1_ESDHC4_CLK_SEL (0x1 << 19)
+#define MX50_CCM_CSCMR1_ESDHC3_CLK_SEL_OFFSET (16)
+#define MX50_CCM_CSCMR1_ESDHC3_CLK_SEL_MASK (0x7 << 16)
#define MXC_CCM_CSCMR1_ESDHC3_MSHC2_CLK_SEL_OFFSET (16)
#define MXC_CCM_CSCMR1_ESDHC3_MSHC2_CLK_SEL_MASK (0x3 << 16)
#define MXC_CCM_CSCMR1_SSI1_CLK_SEL_OFFSET (14)
@@ -279,11 +351,11 @@ extern void __iomem *pll4_base;
#define MXC_CCM_CSCMR2_SLIMBUS_COM (0x1 << 9)
#define MXC_CCM_CSCMR2_SLIMBUS_CLK_SEL_OFFSET (6)
#define MXC_CCM_CSCMR2_SLIMBUS_CLK_SEL_MASK (0x7 << 6)
-/* MX51 */
-#define MXC_CCM_CSCMR2_LBD_DI1_IPU_DIV (0x1 << 11)
-#define MXC_CCM_CSCMR2_LBD_DI0_IPU_DIV (0x1 << 10)
-#define MXC_CCM_CSCMR2_LBD_DI1_CLK_SEL (0x1 << 9)
-#define MXC_CCM_CSCMR2_LBD_DI0_CLK_SEL (0x1 << 8)
+/* MX53 */
+#define MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV (0x1 << 11)
+#define MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV (0x1 << 10)
+#define MXC_CCM_CSCMR2_LDB_DI1_CLK_SEL (0x1 << 9)
+#define MXC_CCM_CSCMR2_LDB_DI0_CLK_SEL (0x1 << 8)
#define MXC_CCM_CSCMR2_CAN_CLK_SEL_OFFSET (6)
#define MXC_CCM_CSCMR2_CAN_CLK_SEL_MASK (0x3 << 6)
#define MXC_CCM_CSCMR2_SPDIF1_COM (1 << 5)
@@ -439,6 +511,9 @@ extern void __iomem *pll4_base;
#define MXC_CCM_CDHIPR_AXI_A_PODF_BUSY (1 << 0)
/* Define the bits in register CDCR */
+#define MX50_CCM_CDCR_SW_PERIPH_CLK_DIV_REQ_STATUS (0x1 << 7)
+#define MX50_CCM_CDCR_SW_PERIPH_CLK_DIV_REQ (0x1 << 6)
+#define MX50_CCM_CDCR_SW_DVFS_EN (0x1 << 5)
#define MXC_CCM_CDCR_ARM_FREQ_SHIFT_DIVIDER (0x1 << 2)
#define MXC_CCM_CDCR_PERIPH_CLK_DVFS_PODF_OFFSET (0)
#define MXC_CCM_CDCR_PERIPH_CLK_DVFS_PODF_MASK (0x3)
@@ -453,9 +528,10 @@ extern void __iomem *pll4_base;
#define MXC_CCM_CLPCR_BYPASS_CAN2_LPM_HS (0x1 << 27)
#define MXC_CCM_CLPCR_BYPASS_CAN1_LPM_HS (0x1 << 27)
#define MXC_CCM_CLPCR_BYPASS_SCC_LPM_HS_MX53 (0x1 << 26)
-#define MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX53 (0x1 << 25)
-#define MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX53 (0x1 << 24)
+#define MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS (0x1 << 25)
+#define MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS (0x1 << 24)
#define MXC_CCM_CLPCR_BYPASS_EMI_INT2_LPM_HS (0x1 << 23)
+#define MX50_CCM_CLPCR_BYPASS_RNGB_LPM_HS (0x1 << 23)
#define MXC_CCM_CLPCR_BYPASS_EMI_INT1_LPM_HS (0x1 << 22)
#define MXC_CCM_CLPCR_BYPASS_EMI_SLOW_LPM_HS (0x1 << 21)
#define MXC_CCM_CLPCR_BYPASS_EMI_FAST_LPM_HS (0x1 << 20)
@@ -472,12 +548,13 @@ extern void __iomem *pll4_base;
#define MXC_CCM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5)
#define MXC_CCM_CLPCR_LPSR_CLK_SEL_OFFSET (3)
#define MXC_CCM_CLPCR_LPSR_CLK_SEL_MASK (0x3 << 3)
+#define MXC_CCM_CLPCR_BYPASS_PMIC_VFUNC_READY (0x1 << 2)
#define MXC_CCM_CLPCR_LPM_OFFSET (0)
#define MXC_CCM_CLPCR_LPM_MASK (0x3)
/* Define the bits in register CISR */
#define MXC_CCM_CISR_ARM_PODF_LOADED_MX51 (0x1 << 25)
-#define MXC_CCM_CISR_ARM_PODF_LOADED_MX53 (0x1 << 26)
+#define MXC_CCM_CISR_ARM_PODF_LOADED (0x1 << 26)
#define MXC_CCM_CISR_TEMP_MON_ALARM (0x1 << 25)
#define MXC_CCM_CISR_EMI_CLK_SEL_LOADED (0x1 << 23)
#define MXC_CCM_CISR_PER_CLK_SEL_LOADED (0x1 << 22)
@@ -490,6 +567,7 @@ extern void __iomem *pll4_base;
#define MXC_CCM_CISR_COSC_READY (0x1 << 6)
#define MXC_CCM_CISR_CKIH2_READY (0x1 << 5)
#define MXC_CCM_CISR_CKIH_READY (0x1 << 4)
+#define MX50_CCM_CISR_CAMP1_READY (0x1 << 4)
#define MXC_CCM_CISR_FPM_READY (0x1 << 3)
#define MXC_CCM_CISR_LRF_PLL3 (0x1 << 2)
#define MXC_CCM_CISR_LRF_PLL2 (0x1 << 1)
@@ -499,13 +577,14 @@ extern void __iomem *pll4_base;
#define MXC_CCM_CIMR_MASK_ARM_PODF_LOADED_MX51 (0x1 << 25)
#define MXC_CCM_CIMR_MASK_EMI_PODF_LOADED_MX51 (0x1 << 20)
#define MXC_CCM_CIMR_MASK_AXI_C_PODF_LOADED_MX51 (0x1 << 19)
-#define MXC_CCM_CIMR_MASK_ARM_PODF_LOADED_MX53 (0x1 << 26)
+#define MXC_CCM_CIMR_MASK_ARM_PODF_LOADED (0x1 << 26)
#define MXC_CCM_CIMR_MASK_TEMP_MON_ALARM (0x1 << 25)
#define MXC_CCM_CIMR_MASK_EMI_CLK_SEL_LOADED (0x1 << 23)
#define MXC_CCM_CIMR_MASK_PER_CLK_SEL_LOADED (0x1 << 22)
#define MXC_CCM_CIMR_MASK_NFC_IPG_INT_MEM_PODF_LOADED (0x1 << 21)
#define MXC_CCM_CIMR_MASK_AHB_PODF_LOADED_MX53 (0x1 << 20)
#define MXC_CCM_CIMR_MASK_EMI_SLOW_PODF_LOADED_MX53 (0x1 << 19)
+#define MX50_CCM_CIMR_MASK_WEIM_PODF_LOADED (0x1 << 19)
#define MXC_CCM_CIMR_MASK_AXI_B_PODF_LOADED (0x1 << 18)
#define MXC_CCM_CIMR_MASK_AXI_A_PODF_LOADED (0x1 << 17)
#define MXC_CCM_CIMR_MASK_DIVIDER_LOADED (0x1 << 16)
@@ -513,8 +592,8 @@ extern void __iomem *pll4_base;
#define MXC_CCM_CIMR_MASK_COSC_READY_MX51 (0x1 << 5)
#define MXC_CCM_CIMR_MASK_CKIH_READY (0x1 << 4)
#define MXC_CCM_CIMR_MASK_FPM_READY (0x1 << 3)
-/* MX53 */
-#define MXC_CCM_CIMR_MASK_COSC_READY_MX53 (0x1 << 6)
+/* MX53/MX50 */
+#define MXC_CCM_CIMR_MASK_COSC_READY (0x1 << 6)
#define MXC_CCM_CIMR_MASK_CAMP2_READY (0x1 << 5)
#define MXC_CCM_CIMR_MASK_CAMP1_READY (0x1 << 4)
#define MXC_CCM_CIMR_MASK_LRF_PLL4 (0x1 << 3)
@@ -542,6 +621,13 @@ extern void __iomem *pll4_base;
#define MXC_CCM_CGPR_VL_L2BIST_CLKDIV_OFFSET (0)
#define MXC_CCM_CGPR_VL_L2BIST_CLKDIV_MASK (0x7)
+#define MX50_CCM_CCOSR_CKO1_SLOW_SEL (0x1 << 8)
+#define MX50_CCM_CCOSR_CKO1_EN (0x1 << 7)
+#define MX50_CCM_CCOSR_CKO1_DIV_OFFSET (4)
+#define MX50_CCM_CCOSR_CKO1_DIV_MASK (0x7 << 4)
+#define MX50_CCM_CCOSR_CKO1_SEL_OFFSET (0)
+#define MX50_CCM_CCOSR_CKO1_SEL_MASK (0xF)
+
/* Define the bits in registers CCGRx */
#define MXC_CCM_CCGR_CG_MASK 0x3
@@ -729,6 +815,82 @@ extern void __iomem *pll4_base;
#define MXC_CCM_CCGR7_CG1_OFFSET 2
#define MXC_CCM_CCGR7_CG0_OFFSET 0
+/* Define the bits in registers CSR2 */
+#define MXC_CCM_CSR2_ELCDIF_PIX_BUSY (0x1 << 9)
+#define MXC_CCM_CSR2_EPDC_PIX_BUSY (0x1 << 8)
+#define MXC_CCM_CSR2_EPDC_AXI_BUSY (0x1 << 4)
+#define MXC_CCM_CSR2_DISPLAY_AXI_BUSY (0x1 << 3)
+
+/* Define the bits in registers CLKSEQ_BYPASS */
+#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_ELCDIF_PIX_CLK_SEL_OFFSET 14
+#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_ELCDIF_PIX_CLK_SEL_MASK (0x3 << 14)
+#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_PIX_CLK_SEL_OFFSET 12
+#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_PIX_CLK_SEL_MASK (0x3 << 12)
+#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_AXI_CLK_SEL_OFFSET 4
+#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_AXI_CLK_SEL_MASK (0x3 << 4)
+#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_DISPLAY_AXI_CLK_SEL_OFFSET 2
+#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_DISPLAY_AXI_CLK_SEL_MASK (0x3 << 2)
+
+
+/* Define the bits in registers CLK_SYS */
+#define MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_OFFSET (30)
+#define MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_MASK (0x3 << 30)
+#define MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_OFFSET (28)
+#define MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_MASK (0x3 << 28)
+#define MXC_CCM_CLK_SYS_DIV_XTAL_OFFSET (6)
+#define MXC_CCM_CLK_SYS_DIV_XTAL_MASK (0xF << 6)
+#define MXC_CCM_CLK_SYS_DIV_PLL_OFFSET (0)
+#define MXC_CCM_CLK_SYS_DIV_PLL_MASK (0x3F)
+
+
+/* Define the bits in registers CLK_DDR */
+#define MXC_CCM_CLK_DDR_DDR_CLKGATE_OFFSET (30)
+#define MXC_CCM_CLK_DDR_DDR_CLKGATE_MASK (0x3 << 30)
+#define MXC_CCM_CLK_DDR_DDR_PFD_SEL (1 << 6)
+#define MXC_CCM_CLK_DDR_DDR_DIV_PLL_OFFSET (0)
+#define MXC_CCM_CLK_DDR_DDR_DIV_PLL_MASK (0x3F)
+
+/* Define the bits in register DISPLAY_AXI */
+#define MXC_CCM_DISPLAY_AXI_CLKGATE_OFFSET (30)
+#define MXC_CCM_DISPLAY_AXI_CLKGATE_MASK (0x3 << 30)
+#define MXC_CCM_DISPLAY_AXI_DIV_OFFSET (0)
+#define MXC_CCM_DISPLAY_AXI_DIV_MASK (0x3F)
+
+/* Define the bits in register EPDC_AXI */
+#define MXC_CCM_EPDC_AXI_CLKGATE_OFFSET (30)
+#define MXC_CCM_EPDC_AXI_CLKGATE_MASK (0x3 << 30)
+#define MXC_CCM_EPDC_AXI_DIV_OFFSET (0)
+#define MXC_CCM_EPDC_AXI_DIV_MASK (0x3F)
+
+/* Define the bits in register EPDCPIX */
+#define MXC_CCM_EPDC_PIX_CLKGATE_OFFSET (30)
+#define MXC_CCM_EPDC_PIX_CLKGATE_MASK (0x3 << 30)
+#define MXC_CCM_EPDC_PIX_CLK_PRED_OFFSET (12)
+#define MXC_CCM_EPDC_PIX_CLK_PRED_MASK (0x3 << 12)
+#define MXC_CCM_EPDC_PIX_CLK_PODF_OFFSET (0)
+#define MXC_CCM_EPDC_PIX_CLK_PODF_MASK (0xFFF)
+
+/* Define the bits in register ELCDIFPIX */
+#define MXC_CCM_ELCDIFPIX_CLKGATE_OFFSET (30)
+#define MXC_CCM_ELCDIFPIX_CLKGATE_MASK (0x3 << 30)
+#define MXC_CCM_ELCDIFPIX_CLK_PRED_OFFSET (12)
+#define MXC_CCM_ELCDIFPIX_CLK_PRED_MASK (0x3 << 12)
+#define MXC_CCM_ELCDIFPIX_CLK_PODF_OFFSET (0)
+#define MXC_CCM_ELCDIFPIX_CLK_PODF_MASK (0xFFF)
+
+
+/* Define the bits in register GPMI */
+#define MXC_CCM_GPMI_CLKGATE_OFFSET (30)
+#define MXC_CCM_GPMI_CLKGATE_MASK (0x3 << 30)
+#define MXC_CCM_GPMI_CLK_DIV_OFFSET (0)
+#define MXC_CCM_GPMI_CLK_DIV_MASK (0x3F)
+
+/* Define the bits in register BCH */
+#define MXC_CCM_BCH_CLKGATE_OFFSET (30)
+#define MXC_CCM_BCH_CLKGATE_MASK (0x3 << 30)
+#define MXC_CCM_BCH_CLK_DIV_OFFSET (0)
+#define MXC_CCM_BCH_CLK_DIV_MASK (0x3F)
+
#define MXC_GPC_BASE (IO_ADDRESS(GPC_BASE_ADDR))
#define MXC_DPTC_LP_BASE (MXC_GPC_BASE + 0x80)
#define MXC_DPTC_GP_BASE (MXC_GPC_BASE + 0x100)
@@ -787,11 +949,12 @@ extern void __iomem *arm_plat_base;
#define MXC_DVFSPER_PMCR1 (MXC_DVFS_PER_BASE + 0x1C)
/* GPC */
-#define MXC_GPC_CNTR (MXC_GPC_BASE + 0x0)
-#define MXC_GPC_PGR (MXC_GPC_BASE + 0x4)
-#define MXC_GPC_VCR (MXC_GPC_BASE + 0x8)
-#define MXC_GPC_ALL_PU (MXC_GPC_BASE + 0xC)
-#define MXC_GPC_NEON (MXC_GPC_BASE + 0x10)
+#define MXC_GPC_CNTR (MXC_GPC_BASE + 0x0)
+#define MXC_GPC_PGR (MXC_GPC_BASE + 0x4)
+#define MXC_GPC_VCR (MXC_GPC_BASE + 0x8)
+#define MXC_GPC_CNTR_OFFSET 0x0
+#define MXC_GPC_PGR_OFFSET 0x4
+#define MXC_GPC_VCR_OFFSET 0x8
/* PGC */
#define MXC_PGC_IPU_PGCR (MXC_PGC_IPU_BASE + 0x0)
diff --git a/arch/arm/mach-mx5/devices.c b/arch/arm/mach-mx5/devices.c
index 06f16db88993..09188c771c9d 100644
--- a/arch/arm/mach-mx5/devices.c
+++ b/arch/arm/mach-mx5/devices.c
@@ -17,17 +17,20 @@
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/ipu.h>
+#include <linux/fb.h>
#include <linux/delay.h>
#include <linux/uio_driver.h>
#include <linux/mxc_scc2_driver.h>
#include <linux/iram_alloc.h>
+#include <linux/gpmi-nfc.h>
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
#include <mach/sdma.h>
-#include "crm_regs.h"
#include "mx51_pins.h"
#include "devices.h"
+#include "dma-apbh.h"
/* Flag used to indicate when IRAM has been initialized */
int iram_ready;
@@ -95,6 +98,11 @@ struct platform_device mxc_keypad_device = {
.resource = mxc_kpp_resources,
};
+struct platform_device mxc_powerkey_device = {
+ .name = "mxcpwrkey",
+ .id = 0,
+};
+
static struct resource rtc_resources[] = {
{
.start = SRTC_BASE_ADDR,
@@ -114,9 +122,80 @@ struct platform_device mxc_rtc_device = {
.resource = rtc_resources,
};
+static struct resource mxc_nand_resources[] = {
+ {
+ .flags = IORESOURCE_MEM,
+ .name = "NFC_AXI_BASE",
+ .start = MX51_NFC_BASE_ADDR_AXI,
+ .end = MX51_NFC_BASE_ADDR_AXI + SZ_8K - 1,
+ },
+ {
+ .flags = IORESOURCE_MEM,
+ .name = "NFC_IP_BASE",
+ .start = NFC_BASE_ADDR + 0x00,
+ .end = NFC_BASE_ADDR + 0x34 - 1,
+ },
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = MXC_INT_NFC,
+ .end = MXC_INT_NFC,
+ },
+};
+
struct platform_device mxc_nandv2_mtd_device = {
.name = "mxc_nandv2_flash",
.id = 0,
+ .resource = mxc_nand_resources,
+ .num_resources = ARRAY_SIZE(mxc_nand_resources),
+};
+
+static struct resource gpmi_nfc_resources[] = {
+ {
+ .name = GPMI_NFC_GPMI_REGS_ADDR_RES_NAME,
+ .flags = IORESOURCE_MEM,
+ .start = GPMI_BASE_ADDR,
+ .end = GPMI_BASE_ADDR + SZ_8K - 1,
+ },
+ {
+ .name = GPMI_NFC_GPMI_INTERRUPT_RES_NAME,
+ .flags = IORESOURCE_IRQ,
+ .start = MXC_INT_RAWNAND_GPMI,
+ .end = MXC_INT_RAWNAND_GPMI,
+ },
+ {
+ .name = GPMI_NFC_BCH_REGS_ADDR_RES_NAME,
+ .flags = IORESOURCE_MEM,
+ .start = BCH_BASE_ADDR,
+ .end = BCH_BASE_ADDR + SZ_8K - 1,
+ },
+ {
+ .name = GPMI_NFC_BCH_INTERRUPT_RES_NAME,
+ .flags = IORESOURCE_IRQ,
+ .start = MXC_INT_RAWNAND_BCH,
+ .end = MXC_INT_RAWNAND_BCH,
+ },
+ {
+ .name = GPMI_NFC_DMA_CHANNELS_RES_NAME,
+ .flags = IORESOURCE_DMA,
+ .start = MXS_DMA_CHANNEL_AHB_APBH_GPMI0,
+ .end = MXS_DMA_CHANNEL_AHB_APBH_GPMI7,
+ },
+ {
+ .name = GPMI_NFC_DMA_INTERRUPT_RES_NAME,
+ .flags = IORESOURCE_IRQ,
+ .start = MXC_INT_APBHDMA_CHAN0,
+ .end = MXC_INT_APBHDMA_CHAN7,
+ },
+};
+
+struct platform_device gpmi_nfc_device = {
+ .name = GPMI_NFC_DRIVER_NAME,
+ .id = 0,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = gpmi_nfc_resources,
+ .num_resources = ARRAY_SIZE(gpmi_nfc_resources),
};
static struct resource imx_nfc_resources[] = {
@@ -213,6 +292,46 @@ struct platform_device mxc_pwm_backlight_device = {
.id = -1,
};
+static struct resource flexcan0_resources[] = {
+ {
+ .start = CAN1_BASE_ADDR,
+ .end = CAN1_BASE_ADDR + 0x3FFF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_CAN1,
+ .end = MXC_INT_CAN1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device mxc_flexcan0_device = {
+ .name = "FlexCAN",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(flexcan0_resources),
+ .resource = flexcan0_resources,
+};
+
+static struct resource flexcan1_resources[] = {
+ {
+ .start = CAN2_BASE_ADDR,
+ .end = CAN2_BASE_ADDR + 0x3FFF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_CAN2,
+ .end = MXC_INT_CAN2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device mxc_flexcan1_device = {
+ .name = "FlexCAN",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(flexcan1_resources),
+ .resource = flexcan1_resources,
+};
+
static struct resource ipu_resources[] = {
{
.start = MX51_IPU_CTRL_BASE_ADDR,
@@ -236,6 +355,52 @@ struct platform_device mxc_ipu_device = {
.resource = ipu_resources,
};
+static struct resource epdc_resources[] = {
+ {
+ .start = EPDC_BASE_ADDR,
+ .end = EPDC_BASE_ADDR + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_EPDC,
+ .end = MXC_INT_EPDC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device epdc_device = {
+ .name = "mxc_epdc_fb",
+ .id = -1,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .num_resources = ARRAY_SIZE(epdc_resources),
+ .resource = epdc_resources,
+};
+
+static struct resource elcdif_resources[] = {
+ {
+ .start = ELCDIF_BASE_ADDR,
+ .end = ELCDIF_BASE_ADDR + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_ELCDIF,
+ .end = MXC_INT_ELCDIF,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device elcdif_device = {
+ .name = "mxc_elcdif_fb",
+ .id = -1,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .num_resources = ARRAY_SIZE(elcdif_resources),
+ .resource = elcdif_resources,
+};
+
struct platform_device mxc_fb_devices[] = {
{
.name = "mxc_sdc_fb",
@@ -260,11 +425,37 @@ struct platform_device mxc_fb_devices[] = {
},
};
-struct platform_device lcd_pdev = {
- .name = "ccwmx51_display",
- .dev = {
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
+static struct resource ldb_resources[] = {
+ {
+ .start = IOMUXC_BASE_ADDR,
+ .end = IOMUXC_BASE_ADDR + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device mxc_ldb_device = {
+ .name = "mxc_ldb",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(ldb_resources),
+ .resource = ldb_resources,
+};
+
+
+struct platform_device lcd_pdev[] = {
+ {
+ .name = "ccwmx51_display",
+ .id = 0,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ },
+ {
+ .name = "ccwmx51_display",
+ .id = 1,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ },
};
static struct resource vpu_resources[] = {
@@ -307,6 +498,53 @@ struct platform_device mxcscc_device = {
.resource = scc_resources,
};
+static struct resource dcp_resources[] = {
+
+ {
+ .flags = IORESOURCE_MEM,
+ .start = DCP_BASE_ADDR,
+ .end = DCP_BASE_ADDR + 0x2000 - 1,
+ }, {
+ .flags = IORESOURCE_IRQ,
+ .start = MXC_INT_DCP_CHAN0,
+ .end = MXC_INT_DCP_CHAN0,
+ }, {
+ .flags = IORESOURCE_IRQ,
+ .start = MXC_INT_DCP_CHAN1_3,
+ .end = MXC_INT_DCP_CHAN1_3,
+ },
+};
+
+struct platform_device dcp_device = {
+ .name = "dcp",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(dcp_resources),
+ .resource = dcp_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+
+static struct resource rngb_resources[] = {
+ {
+ .start = RNGB_BASE_ADDR,
+ .end = RNGB_BASE_ADDR + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_RNGB_BLOCK,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/* the RNGC driver applies for MX50's RNGB hw */
+struct platform_device mxc_rngb_device = {
+ .name = "fsl_rngc",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(rngb_resources),
+ .resource = rngb_resources,
+};
static struct resource mxc_fec_resources[] = {
{
@@ -508,6 +746,26 @@ struct platform_device mxc_ssi2_device = {
.resource = ssi2_resources,
};
+static struct resource esai_resources[] = {
+ {
+ .start = ESAI_BASE_ADDR,
+ .end = ESAI_BASE_ADDR + 0x100,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_ESAI,
+ .end = MXC_INT_ESAI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device mxc_esai_device = {
+ .name = "mxc_esai",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(esai_resources),
+ .resource = esai_resources,
+};
+
static struct resource tve_resources[] = {
{
.start = TVE_BASE_ADDR,
@@ -623,6 +881,8 @@ int __init mxc_register_gpios(void)
{
if (cpu_is_mx51())
return mxc_gpio_init(mxc_gpio_ports, 4);
+ else if (cpu_is_mx50())
+ return mxc_gpio_init(mxc_gpio_ports, 6);
return mxc_gpio_init(mxc_gpio_ports, ARRAY_SIZE(mxc_gpio_ports));
}
@@ -803,9 +1063,58 @@ struct platform_device pata_fsl_device = {
},
};
+/* On-Chip OTP device and resource */
+static struct resource otp_resource = {
+ .start = OCOTP_CTRL_BASE_ADDR,
+ .end = OCOTP_CTRL_BASE_ADDR + SZ_8K - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+struct platform_device fsl_otp_device = {
+ .name = "ocotp",
+ .id = -1,
+ .resource = &otp_resource,
+ .num_resources = 1,
+};
+
+static struct resource ahci_fsl_resources[] = {
+ {
+ .start = MX53_SATA_BASE_ADDR,
+ .end = MX53_SATA_BASE_ADDR + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_SATA,
+ .end = MXC_INT_SATA,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device ahci_fsl_device = {
+ .name = "ahci",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(ahci_fsl_resources),
+ .resource = ahci_fsl_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
static u64 usb_dma_mask = DMA_BIT_MASK(32);
-static struct resource usbotg_resources[] = {
+static struct resource usbotg_host_resources[] = {
+ {
+ .start = OTG_BASE_ADDR,
+ .end = OTG_BASE_ADDR + 0x1ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_USB_OTG,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource usbotg_udc_resources[] = {
{
.start = OTG_BASE_ADDR,
.end = OTG_BASE_ADDR + 0x1ff,
@@ -836,8 +1145,8 @@ struct platform_device mxc_usbdr_udc_device = {
.dma_mask = &usb_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
- .resource = usbotg_resources,
- .num_resources = ARRAY_SIZE(usbotg_resources),
+ .resource = usbotg_udc_resources,
+ .num_resources = ARRAY_SIZE(usbotg_udc_resources),
};
struct platform_device mxc_usbdr_otg_device = {
@@ -854,8 +1163,8 @@ struct platform_device mxc_usbdr_otg_device = {
struct platform_device mxc_usbdr_host_device = {
.name = "fsl-ehci",
.id = 0,
- .num_resources = ARRAY_SIZE(usbotg_resources),
- .resource = usbotg_resources,
+ .num_resources = ARRAY_SIZE(usbotg_host_resources),
+ .resource = usbotg_host_resources,
.dev = {
.dma_mask = &usb_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
@@ -970,23 +1279,31 @@ static struct resource mxc_gpu2d_resources[] = {
#if defined(CONFIG_UIO_PDRV_GENIRQ) || defined(CONFIG_UIO_PDRV_GENIRQ_MODULE)
static struct clk *gpu_clk;
+static atomic_t *gpu_use_count;
int gpu2d_open(struct uio_info *info, struct inode *inode)
{
- gpu_clk = clk_get(NULL, "gpu2d_clk");
- if (IS_ERR(gpu_clk))
- return PTR_ERR(gpu_clk);
+ int err = 0;
+
+ if (atomic_inc_return(gpu_use_count) == 1) {
+ gpu_clk = clk_get(NULL, "gpu2d_clk");
+ if (IS_ERR(gpu_clk))
+ err = PTR_ERR(gpu_clk);
- return clk_enable(gpu_clk);
+ err = clk_enable(gpu_clk);
+ }
+ return err;
}
int gpu2d_release(struct uio_info *info, struct inode *inode)
{
- if (IS_ERR(gpu_clk))
- return PTR_ERR(gpu_clk);
+ if (atomic_dec_and_test(gpu_use_count)) {
+ if (IS_ERR(gpu_clk))
+ return PTR_ERR(gpu_clk);
- clk_disable(gpu_clk);
- clk_put(gpu_clk);
+ clk_disable(gpu_clk);
+ clk_put(gpu_clk);
+ }
return 0;
}
@@ -1027,8 +1344,11 @@ static struct platform_device mxc_gpu2d_device = {
static inline void mxc_init_gpu2d(void)
{
- dma_alloc_coherent(&mxc_gpu2d_device.dev, SZ_8K, &mxc_gpu2d_resources[1].start, GFP_DMA);
- mxc_gpu2d_resources[1].end = mxc_gpu2d_resources[1].start + SZ_8K - 1;
+ void *gpu_mem;
+ gpu_mem = dma_alloc_coherent(&mxc_gpu2d_device.dev, SZ_64K, &mxc_gpu2d_resources[1].start, GFP_DMA);
+ mxc_gpu2d_resources[1].end = mxc_gpu2d_resources[1].start + SZ_64K - 1;
+ memset(gpu_mem, 0, SZ_64K);
+ gpu_use_count = gpu_mem + SZ_64K - 4;
dma_alloc_coherent(&mxc_gpu2d_device.dev, 88 * SZ_1K, &mxc_gpu2d_resources[2].start, GFP_DMA);
mxc_gpu2d_resources[2].end = mxc_gpu2d_resources[2].start + (88 * SZ_1K) - 1;
@@ -1041,6 +1361,118 @@ static inline void mxc_init_gpu2d(void)
}
#endif
+static struct resource mlb_resources[] = {
+ [0] = {
+ .start = MLB_BASE_ADDR,
+ .end = MLB_BASE_ADDR + 0x300,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = MXC_INT_MLB,
+ .end = MXC_INT_MLB,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device mxc_mlb_device = {
+ .name = "mxc_mlb",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(mlb_resources),
+ .resource = mlb_resources,
+};
+
+static struct resource pxp_resources[] = {
+ {
+ .start = EPXP_BASE_ADDR,
+ .end = EPXP_BASE_ADDR + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MXC_INT_EPXP,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device mxc_pxp_device = {
+ .name = "mxc-pxp",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(pxp_resources),
+ .resource = pxp_resources,
+};
+
+struct platform_device mxc_pxp_client_device = {
+ .name = "pxp-device",
+ .id = -1,
+};
+
+static u64 pxp_dma_mask = DMA_BIT_MASK(32);
+struct platform_device mxc_pxp_v4l2 = {
+ .name = "pxp-v4l2",
+ .id = -1,
+ .dev = {
+ .dma_mask = &pxp_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+struct platform_device mxc_v4l2_device = {
+ .name = "mxc_v4l2_capture",
+ .id = 0,
+};
+
+struct platform_device mxc_v4l2out_device = {
+ .name = "mxc_v4l2_output",
+ .id = 0,
+};
+
+struct resource viim_resources[] = {
+ [0] = {
+ .start = (GPT1_BASE_ADDR - 0x20000000),
+ .end = (GPT1_BASE_ADDR - 0x20000000) + PAGE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = OCOTP_CTRL_BASE_ADDR,
+ .end = OCOTP_CTRL_BASE_ADDR + PAGE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+struct platform_device mxs_viim = {
+ .name = "mxs_viim",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(viim_resources),
+ .resource = viim_resources,
+};
+
+static struct resource dma_apbh_resources[] = {
+ {
+ .start = APBHDMA_BASE_ADDR,
+ .end = APBHDMA_BASE_ADDR + 0x2000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device mxs_dma_apbh_device = {
+ .name = "mxs-dma-apbh",
+ .num_resources = ARRAY_SIZE(dma_apbh_resources),
+ .resource = dma_apbh_resources,
+};
+
+struct platform_device mxc_android_pmem_device = {
+ .name = "android_pmem",
+ .id = 0,
+};
+
+struct platform_device mxc_android_pmem_gpu_device = {
+ .name = "android_pmem",
+ .id = 1,
+};
+
+struct platform_device android_usb_device = {
+ .name = "android_usb",
+ .id = -1,
+};
+
void __init mx5_init_irq(void)
{
unsigned long tzic_addr;
@@ -1049,7 +1481,7 @@ void __init mx5_init_irq(void)
tzic_addr = MX51_TZIC_BASE_ADDR_T01;
else if (cpu_is_mx51_rev(CHIP_REV_2_0) > 0)
tzic_addr = MX51_TZIC_BASE_ADDR;
- else /* mx53 */
+ else /* mx53 and mx50 */
tzic_addr = MX53_TZIC_BASE_ADDR;
mxc_tzic_init_irq(tzic_addr);
@@ -1266,7 +1698,7 @@ exit:
int __init mxc_init_devices(void)
{
- if (cpu_is_mx53()) {
+ if (cpu_is_mx53() || cpu_is_mx50()) {
sdma_resources[0].start -= MX53_OFFSET;
sdma_resources[0].end -= MX53_OFFSET;
mxc_w1_master_resources[0].start -= MX53_OFFSET;
@@ -1287,6 +1719,10 @@ int __init mxc_init_devices(void)
pwm1_resources[0].end -= MX53_OFFSET;
pwm2_resources[0].start -= MX53_OFFSET;
pwm2_resources[0].end -= MX53_OFFSET;
+ flexcan0_resources[0].start -= MX53_OFFSET;
+ flexcan0_resources[0].end -= MX53_OFFSET;
+ flexcan1_resources[0].start -= MX53_OFFSET;
+ flexcan1_resources[0].end -= MX53_OFFSET;
mxc_fec_resources[0].start -= MX53_OFFSET;
mxc_fec_resources[0].end -= MX53_OFFSET;
vpu_resources[0].start -= MX53_OFFSET;
@@ -1295,6 +1731,8 @@ int __init mxc_init_devices(void)
scc_resources[0].end -= MX53_OFFSET;
scc_resources[1].start = MX53_SCC_RAM_BASE_ADDR;
scc_resources[1].end = MX53_SCC_RAM_BASE_ADDR + SZ_16K - 1;
+ rngb_resources[0].start -= MX53_OFFSET;
+ rngb_resources[0].end -= MX53_OFFSET;
mxcspi1_resources[0].start -= MX53_OFFSET;
mxcspi1_resources[0].end -= MX53_OFFSET;
mxcspi2_resources[0].start -= MX53_OFFSET;
@@ -1311,8 +1749,12 @@ int __init mxc_init_devices(void)
ssi1_resources[0].end -= MX53_OFFSET;
ssi2_resources[0].start -= MX53_OFFSET;
ssi2_resources[0].end -= MX53_OFFSET;
+ esai_resources[0].start -= MX53_OFFSET;
+ esai_resources[0].end -= MX53_OFFSET;
tve_resources[0].start -= MX53_OFFSET;
tve_resources[0].end -= MX53_OFFSET;
+ dvfs_core_resources[0].start -= MX53_OFFSET;
+ dvfs_core_resources[0].end -= MX53_OFFSET;
dvfs_per_resources[0].start -= MX53_OFFSET;
dvfs_per_resources[0].end -= MX53_OFFSET;
spdif_resources[0].start -= MX53_OFFSET;
@@ -1331,8 +1773,10 @@ int __init mxc_init_devices(void)
mxcsdhc2_resources[0].end -= MX53_OFFSET;
mxcsdhc3_resources[0].start -= MX53_OFFSET;
mxcsdhc3_resources[0].end -= MX53_OFFSET;
- usbotg_resources[0].start -= MX53_OFFSET;
- usbotg_resources[0].end -= MX53_OFFSET;
+ usbotg_host_resources[0].start -= MX53_OFFSET;
+ usbotg_host_resources[0].end -= MX53_OFFSET;
+ usbotg_udc_resources[0].start -= MX53_OFFSET;
+ usbotg_udc_resources[0].end -= MX53_OFFSET;
usbotg_xcvr_resources[0].start -= MX53_OFFSET;
usbotg_xcvr_resources[0].end -= MX53_OFFSET;
usbh1_resources[0].start -= MX53_OFFSET;
@@ -1341,19 +1785,40 @@ int __init mxc_init_devices(void)
usbh2_resources[0].end -= MX53_OFFSET;
mxc_gpu_resources[2].start = MX53_GPU2D_BASE_ADDR;
mxc_gpu_resources[2].end = MX53_GPU2D_BASE_ADDR + SZ_4K - 1;
- mxc_gpu_resources[4].start = MX53_GPU_GMEM_BASE_ADDR;
- mxc_gpu_resources[4].end = MX53_GPU_GMEM_BASE_ADDR + SZ_256K - 1;
mxc_gpu2d_resources[0].start = MX53_GPU2D_BASE_ADDR;
mxc_gpu2d_resources[0].end = MX53_GPU2D_BASE_ADDR + SZ_4K - 1;
+ if (cpu_is_mx53()) {
+ mxc_gpu_resources[4].start = MX53_GPU_GMEM_BASE_ADDR;
+ mxc_gpu_resources[4].end = MX53_GPU_GMEM_BASE_ADDR
+ + SZ_256K - 1;
+ } else {
+ mxc_gpu_resources[1].start = 0;
+ mxc_gpu_resources[1].end = 0;
+ mxc_gpu_resources[3].start = 0;
+ mxc_gpu_resources[3].end = 0;
+ mxc_gpu_resources[4].start = 0;
+ mxc_gpu_resources[4].end = 0;
+ }
ipu_resources[0].start = MX53_IPU_CTRL_BASE_ADDR;
ipu_resources[0].end = MX53_IPU_CTRL_BASE_ADDR + SZ_128M - 1;
+ mlb_resources[0].start -= MX53_OFFSET;
+ mlb_resources[0].end -= MX53_OFFSET;
+ mxc_nandv2_mtd_device.resource[0].start =
+ MX53_NFC_BASE_ADDR_AXI;
+ mxc_nandv2_mtd_device.resource[0].end =
+ MX53_NFC_BASE_ADDR_AXI + SZ_8K - 1;
+ mxc_nandv2_mtd_device.resource[1].start -= MX53_OFFSET;
+ mxc_nandv2_mtd_device.resource[1].end -= MX53_OFFSET;
+ ldb_resources[0].start -= MX53_OFFSET;
+ ldb_resources[0].end -= MX53_OFFSET;
} else if (cpu_is_mx51_rev(CHIP_REV_2_0) < 0) {
scc_resources[1].start += 0x8000;
scc_resources[1].end += 0x8000;
}
+ if (cpu_is_mx51() || cpu_is_mx53())
+ mxc_init_scc_iram();
- mxc_init_scc_iram();
mxc_init_gpu2d();
#if defined (CONFIG_MACH_CCWMX51JS)
ccwmx51_init_devices();
diff --git a/arch/arm/mach-mx5/devices.h b/arch/arm/mach-mx5/devices.h
index 13b9c2838fd5..da6c6ac96428 100644
--- a/arch/arm/mach-mx5/devices.h
+++ b/arch/arm/mach-mx5/devices.h
@@ -27,8 +27,11 @@ extern struct platform_device mxc_wdt_device;
extern struct platform_device mxc_pwm1_device;
extern struct platform_device mxc_pwm2_device;
extern struct platform_device mxc_pwm_backlight_device;
+extern struct platform_device mxc_flexcan0_device;
+extern struct platform_device mxc_flexcan1_device;
extern struct platform_device mxc_ipu_device;
extern struct platform_device mxc_fb_devices[];
+extern struct platform_device mxc_ldb_device;
extern struct platform_device mxcvpu_device;
extern struct platform_device mxcscc_device;
extern struct platform_device mxcspi1_device;
@@ -41,6 +44,7 @@ extern struct platform_device mxc_dvfs_core_device;
extern struct platform_device mxc_dvfs_per_device;
extern struct platform_device mxc_ssi1_device;
extern struct platform_device mxc_ssi2_device;
+extern struct platform_device mxc_esai_device;
extern struct platform_device mxc_alsa_spdif_device;
extern struct platform_device mx51_lpmode_device;
extern struct platform_device mx53_lpmode_device;
@@ -51,7 +55,9 @@ extern struct platform_device mxc_sim_device;
extern struct platform_device mxcsdhc1_device;
extern struct platform_device mxcsdhc2_device;
extern struct platform_device mxcsdhc3_device;
+extern struct platform_device ahci_fsl_device;
extern struct platform_device pata_fsl_device;
+extern struct platform_device fsl_otp_device;
extern struct platform_device gpu_device;
extern struct platform_device mxc_fec_device;
extern struct platform_device mxc_usbdr_udc_device;
@@ -59,6 +65,25 @@ extern struct platform_device mxc_usbdr_otg_device;
extern struct platform_device mxc_usbdr_host_device;
extern struct platform_device mxc_usbh1_device;
extern struct platform_device mxc_usbh2_device;
-extern struct platform_device lcd_pdev;
+extern struct platform_device lcd_pdev[];
extern struct platform_device mxc_wm8753_device;
+extern struct platform_device mxc_mlb_device;
extern void __init ccwmx51_init_devices ( void );
+extern struct platform_device mxc_nandv2_mtd_device;
+extern struct platform_device mxc_pxp_device;
+extern struct platform_device mxc_pxp_client_device;
+extern struct platform_device mxc_pxp_v4l2;
+extern struct platform_device epdc_device;
+extern struct platform_device elcdif_device;
+extern struct platform_device mxc_v4l2_device;
+extern struct platform_device mxc_v4l2out_device;
+extern struct platform_device mxs_viim;
+extern struct platform_device mxs_dma_apbh_device;
+extern struct platform_device gpmi_nfc_device;
+extern struct platform_device mxc_rngb_device;
+extern struct platform_device dcp_device;
+extern struct platform_device mxc_android_pmem_device;
+extern struct platform_device mxc_android_pmem_gpu_device;
+extern struct platform_device android_usb_device;
+extern struct platform_device mxc_powerkey_device;
+extern struct platform_device ccwmx51js_keys_gpio;
diff --git a/arch/arm/mach-mx5/devices_ccwmx51.c b/arch/arm/mach-mx5/devices_ccwmx51.c
index 4e4a07f7c4a7..27eb3dc32064 100644
--- a/arch/arm/mach-mx5/devices_ccwmx51.c
+++ b/arch/arm/mach-mx5/devices_ccwmx51.c
@@ -25,6 +25,7 @@
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
#include <linux/i2c.h>
#include <linux/ata.h>
#include <linux/regulator/consumer.h>
@@ -34,6 +35,7 @@
#include <linux/mxcfb.h>
#include <linux/pwm_backlight.h>
#include <linux/smsc911x.h>
+#include <linux/sysfs.h>
#include <mach/common.h>
#include <mach/hardware.h>
#include <asm/irq.h>
@@ -45,6 +47,7 @@
#include <mach/gpio.h>
#include <mach/mmc.h>
#include <mach/mxc_dvfs.h>
+#include <video/ad9389.h>
#include "board-ccwmx51.h"
#include "iomux.h"
#include "crm_regs.h"
@@ -52,6 +55,8 @@
#include "mx51_pins.h"
#include "displays/displays.h"
#include <linux/smc911x.h>
+#include <linux/fec.h>
+#include <linux/gpio_keys.h>
#if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE)
#include <linux/mtd/mtd.h>
@@ -60,65 +65,159 @@
#include <asm/mach/flash.h>
#endif
-#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)
+#if defined(CONFIG_VIDEO_AD9389) || defined(CONFIG_VIDEO_AD9389_MODULE)
+static int debug = 0;
+#endif
-extern void gpio_nand_active(void);
-extern void gpio_nand_inactive(void);
+#define AD9389_DBG 0x0001
+#define DBG(flag, fmt, args...) do { \
+ if (debug & flag) \
+ printk(fmt, ## args); \
+ } while (0)
-static int nand_init(void)
+static u8 ccwmx51_mod_variant = 0;
+static u8 ccwmx51_mod_rev = 0;
+static u32 ccwmx51_mod_sn = 0;
+static u8 ccwmx51_bb_rev = BASE_BOARD_REV;
+
+void ccwmx51_set_mod_variant(u8 variant)
{
- /* Configure the pins */
- gpio_nand_active();
- return 0;
+ ccwmx51_mod_variant = variant;
+}
+void ccwmx51_set_mod_revision(u8 revision)
+{
+ ccwmx51_mod_rev = revision;
+}
+void ccwmx51_set_mod_sn(u32 sn)
+{
+ ccwmx51_mod_sn = sn;
}
-static void nand_exit(void)
+#ifdef CONFIG_SYSFS
+static ssize_t ccwmx51_mod_variant_attr_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
{
- /* Free the pins */
- gpio_nand_inactive();
+ return snprintf(buf, PAGE_SIZE, "%d\n", ccwmx51_mod_variant);
}
-struct flash_platform_data mxc_nand_data = {
- .width = 1,
- .init = nand_init,
- .exit = nand_exit,
-};
-#endif
+static ssize_t ccwmx51_mod_rev_attr_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", ccwmx51_mod_rev);
+}
-#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
-struct smsc911x_platform_config ccwmx51_smsc9118 = {
- .flags = SMSC911X_USE_32BIT,
- .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
- .irq_type = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, /* push-pull irq */
-};
-#endif
+static ssize_t ccwmx51_mod_sn_attr_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", ccwmx51_mod_sn);
+}
+
+static ssize_t cccwmx51_bb_rev_attr_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", ccwmx51_bb_rev);
+}
+
+static struct kobj_attribute ccwmx51_mod_variant_attr =
+ __ATTR(mod_variant, S_IRUGO, ccwmx51_mod_variant_attr_show, NULL);
+static struct kobj_attribute ccwmx51_mod_rev_attr =
+ __ATTR(mod_rev, S_IRUGO, ccwmx51_mod_rev_attr_show, NULL);
+static struct kobj_attribute ccwmx51_mod_sn_attr =
+ __ATTR(mod_sn, S_IRUGO, ccwmx51_mod_sn_attr_show, NULL);
+static struct kobj_attribute ccwmx51_bb_rev_attr =
+ __ATTR(bb_rev, S_IRUGO, cccwmx51_bb_rev_attr_show, NULL);
+
+int ccwmx51_create_sysfs_entries(void)
+{
+ struct kobject *ccwmx51_kobj;
+ int ret;
+
+ ccwmx51_kobj = kobject_create_and_add("ccwmx51", kernel_kobj);
+ if (!ccwmx51_kobj) {
+ printk(KERN_WARNING "kobject_create_and_add ccwmx51 failed\n");
+ return -EINVAL;
+ }
+
+ ret = sysfs_create_file(ccwmx51_kobj, &ccwmx51_mod_variant_attr.attr);
+ if (ret) {
+ printk(KERN_ERR
+ "Unable to register sysdev entry for ccwmx51 hardware variant\n");
+ return ret;
+ }
+ ret = sysfs_create_file(ccwmx51_kobj, &ccwmx51_mod_rev_attr.attr);
+ if (ret) {
+ printk(KERN_ERR
+ "Unable to register sysdev entry for ccwmx51 hardware revision\n");
+ return ret;
+ }
+ ret = sysfs_create_file(ccwmx51_kobj, &ccwmx51_mod_sn_attr.attr);
+ if (ret) {
+ printk(KERN_ERR
+ "Unable to register sysdev entry for ccwmx51 hardware SN\n");
+ return ret;
+ }
+ ret = sysfs_create_file(ccwmx51_kobj, &ccwmx51_bb_rev_attr.attr);
+ if (ret) {
+ printk(KERN_ERR
+ "Unable to register sysdev entry for ccwmx51 base board hardware revision\n");
+ return ret;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_SYSFS */
+
+#if defined(CONFIG_HAS_EARLY_USER_LEDS)
+void ccwmx51_user_led(int led, int val)
+{
+ __iomem void *base;
+ u32 reg, mask;
+
+ if (led == 1)
+ mask = 1 << 10;
+ else if (led == 2)
+ mask = 1 << 9;
+ else
+ return;
+
+ base = ioremap(GPIO3_BASE_ADDR, SZ_4K);
+ reg = __raw_readl(base);
+
+ if (val)
+ reg |= mask;
+ else
+ reg &= ~mask;
+
+ __raw_writel(reg, base);
+ iounmap(base);
+}
+#endif /* CONFIG_HAS_EARLY_USER_LEDS */
#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE)
static int sdhc_write_protect(struct device *dev)
{
- unsigned short rc = 0;
+ unsigned short rc = 0;
- if (to_platform_device(dev)->id == 0)
- rc = 0; /* Not supported WP on JSK board, therefore write is enabled */
- else if (to_platform_device(dev)->id == 2)
- rc = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_NANDF_CS1));
- return rc;
+ if (to_platform_device(dev)->id == 0)
+ rc = 0; /* Not supported WP on JSK board, therefore write is enabled */
+ else if (to_platform_device(dev)->id == 2)
+ rc = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_NANDF_CS1));
+ return rc;
}
static unsigned int sdhc_get_card_det_status(struct device *dev)
{
- int ret = 0;
+ int ret = 1;
- if (to_platform_device(dev)->id == 0)
- ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_0));
- else if (to_platform_device(dev)->id == 2)
- ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO_NAND));
- return ret;
+ if (to_platform_device(dev)->id == 0)
+#ifdef CONFIG_JSCCWMX51_V1
+ ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_0));
+#else
+ ret = 0;
+#endif
+ else if (to_platform_device(dev)->id == 2)
+ ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO_NAND));
+ return ret;
}
struct mxc_mmc_platform_data mmc1_data = {
@@ -135,7 +234,7 @@ struct mxc_mmc_platform_data mmc1_data = {
struct mxc_mmc_platform_data mmc3_data = {
.ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 |
- MMC_VDD_31_32,
+ MMC_VDD_31_32,
.caps = MMC_CAP_4_BIT_DATA,
.min_clk = 150000,
.max_clk = 50000000,
@@ -145,12 +244,73 @@ struct mxc_mmc_platform_data mmc3_data = {
.clock_mmc = "esdhc_clk",
.power_mmc = NULL,
};
+
+void ccwmx51_register_sdio(int interface)
+{
+ switch (interface) {
+ case 0:
+ mxcsdhc1_device.resource[2].start = CCWMX51_SD1_CD_IRQ;
+ mxcsdhc1_device.resource[2].end = CCWMX51_SD1_CD_IRQ;
+ mxc_register_device(&mxcsdhc1_device, &mmc1_data);
+ break;
+ case 2:
+ mxcsdhc3_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO_NAND);
+ mxcsdhc3_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO_NAND);
+ mxc_register_device(&mxcsdhc3_device, &mmc3_data);
+ break;
+ }
+}
+#endif
+
+#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();
+}
+
+struct flash_platform_data mxc_nand_data = {
+ .width = 1,
+ .init = nand_init,
+ .exit = nand_exit,
+};
+#endif
+
+#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+struct smsc911x_platform_config ccwmx51_smsc9118 = {
+ .flags = SMSC911X_USE_32BIT,
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+ .irq_type = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, /* push-pull irq */
+};
#endif
#if defined(CONFIG_FB_MXC_SYNC_PANEL) || defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE)
-struct resource mxcfb_resources[1] = {
+struct resource mxcfb_resources[2] = {
{
- .flags = IORESOURCE_MEM,
+ .flags = IORESOURCE_MEM,
+ .start = 0,
+ .end = 0,
+ },
+ {
+ .flags = IORESOURCE_MEM,
+ .start = 0,
+ .end = 0,
},
};
#endif
@@ -158,13 +318,24 @@ struct resource mxcfb_resources[1] = {
static struct i2c_board_info ccwmx51_i2c_devices[] __initdata = {
#if defined(CONFIG_INPUT_MMA7455L) || defined(CONFIG_INPUT_MMA7455L_MODULE)
{
- I2C_BOARD_INFO("mma7455l", 0x1d),
+ I2C_BOARD_INFO("mma7455l", 0x1d),
.irq = IOMUX_TO_IRQ(MX51_PIN_GPIO1_7),
},
#endif
#if defined(CONFIG_SND_SOC_IMX_CCWMX51_WM8753) || defined(CONFIG_SND_SOC_IMX_CCWMX51_WM8753_MODULE)
{
- I2C_BOARD_INFO("wm8753", 0x1A),
+ I2C_BOARD_INFO("wm8753", 0x1A),
+ },
+#endif
+
+#if defined (CONFIG_MXC_CAMERA_MICRON111_1) || defined(CONFIG_MXC_CAMERA_MICRON111_1_MODULE)
+ {
+ I2C_BOARD_INFO("mt9v111_1", 0xB8>>1),
+ },
+#endif
+#if defined (CONFIG_MXC_CAMERA_MICRON111_2) || defined(CONFIG_MXC_CAMERA_MICRON111_2_MODULE)
+ {
+ I2C_BOARD_INFO("mt9v111_2", 0x90>>1),
},
#endif
};
@@ -183,16 +354,54 @@ struct mxc_i2c_platform_data mxci2c_hs_data = {
};
#if defined(CONFIG_SPI_MXC_SELECT1_SS1) && (defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE))
+#if defined(CONFIG_CCWMX51_SECOND_TOUCH)
+static int touch_pendown_state(void)
+{
+ return gpio_get_value(IOMUX_TO_GPIO(SECOND_TS_IRQ_PIN)) ? 0 : 1;
+}
+
+static struct ads7846_platform_data ccwmx51js_touch_data = {
+ .model = 7843,
+ .x_min = 0,
+ .y_min = 0,
+ .x_max = 4095,
+ .y_max = 4095,
+ .get_pendown_state = touch_pendown_state,
+ .buflen = 10,
+ .skip_samples = 2,
+ .rotate = 0,
+};
+
+static struct spi_board_info ccwmx51_2nd_touch[] = {
+ {
+ .modalias = "ads7846",
+ .max_speed_hz = 500000,
+ .irq = IOMUX_TO_IRQ(SECOND_TS_IRQ_PIN),
+ .bus_num = 1,
+ .chip_select = 3,
+ .platform_data = &ccwmx51js_touch_data,
+ },
+};
+
+void ccwmx51_init_2nd_touch(void)
+{
+ ccwmx51_2nd_touch_gpio_init();
+ spi_register_board_info(ccwmx51_2nd_touch, ARRAY_SIZE(ccwmx51_2nd_touch));
+}
+#else
+void ccwmx51_init_2nd_touch(void) {}
+#endif
+
static struct spi_board_info spi_devices[] = {
#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
- { /* SPIDEV */
- .modalias = "spidev",
- .max_speed_hz = 6000000,
- .bus_num = 1,
- .chip_select = 1,
+ { /* SPIDEV */
+ .modalias = "spidev",
+ .max_speed_hz = 6000000,
+ .bus_num = 1,
+ .chip_select = 1,
},
- /* Add here other SPI devices, if any... */
#endif
+ /* Add here other SPI devices, if any... */
};
void ccwmx51_init_spidevices(void)
@@ -234,7 +443,7 @@ struct mxc_w1_config mxc_w1_data = {
#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
static struct resource smsc911x_device_resources[] = {
- {
+ {
.name = "smsc911x-memory",
.start = CS5_BASE_ADDR,
.end = CS5_BASE_ADDR + SZ_4K - 1,
@@ -248,10 +457,10 @@ static struct resource smsc911x_device_resources[] = {
};
struct platform_device smsc911x_device = {
- .name = "smsc911x",
- .id = -1,
- .num_resources = ARRAY_SIZE(smsc911x_device_resources),
- .resource = smsc911x_device_resources,
+ .name = "smsc911x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(smsc911x_device_resources),
+ .resource = smsc911x_device_resources,
};
/* WEIM registers */
@@ -261,9 +470,9 @@ struct platform_device smsc911x_device = {
#define CSRCR2 0x0C
#define CSWCR1 0x10
-static void __init ccwmx51_init_ext_eth_mac(void)
+static void ccwmx51_init_ext_eth_mac(void)
{
- __iomem u32 *weim_vbaddr;
+ __iomem void *weim_vbaddr;
weim_vbaddr = ioremap(WEIM_BASE_ADDR, SZ_4K);
if (weim_vbaddr == 0) {
@@ -276,11 +485,11 @@ static void __init ccwmx51_init_ext_eth_mac(void)
* RWSC=50, RADVA=2, RADVN=6, OEA=0, OEN=0, RCSA=0, RCSN=0, APR=0
* WAL=0, WBED=1, WWSC=50, WADVA=2, WADVN=6, WEA=0, WEN=0, WCSA=0
*/
- writel(0x00420081, (unsigned int)(weim_vbaddr) + 0x78 + CSGCR1);
- writel(0, (unsigned int)(weim_vbaddr) + 0x78 + CSGCR2);
- writel(0x32260000, (unsigned int)(weim_vbaddr) + 0x78 + CSRCR1);
- writel(0, (unsigned int)(weim_vbaddr) + 0x78 + CSRCR2);
- writel(0x72080f00, (unsigned int)(weim_vbaddr) + 0x78 + CSWCR1);
+ __raw_writel(0x00420081, (u32)weim_vbaddr + 0x78 + CSGCR1);
+ __raw_writel(0, (u32)weim_vbaddr + 0x78 + CSGCR2);
+ __raw_writel(0x32260000, (u32)weim_vbaddr + 0x78 + CSRCR1);
+ __raw_writel(0, (u32)weim_vbaddr + 0x78 + CSRCR2);
+ __raw_writel(0x72080f00, (u32)weim_vbaddr + 0x78 + CSWCR1);
iounmap(weim_vbaddr);
@@ -314,15 +523,11 @@ struct mxc_dvfs_platform_data dvfs_core_data = {
.reg_id = "SW1",
.clk1_id = "cpu_clk",
.clk2_id = "gpc_dvfs_clk",
- .gpc_cntr_reg_addr = MXC_GPC_CNTR,
- .gpc_vcr_reg_addr = MXC_GPC_VCR,
- .ccm_cdcr_reg_addr = MXC_CCM_CDCR,
- .ccm_cacrr_reg_addr = MXC_CCM_CACRR,
- .ccm_cdhipr_reg_addr = MXC_CCM_CDHIPR,
- .dvfs_thrs_reg_addr = MXC_DVFSTHRS,
- .dvfs_coun_reg_addr = MXC_DVFSCOUN,
- .dvfs_emac_reg_addr = MXC_DVFSEMAC,
- .dvfs_cntr_reg_addr = MXC_DVFSCNTR,
+ .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET,
+ .gpc_vcr_offset = MXC_GPC_VCR_OFFSET,
+ .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET,
+ .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET,
+ .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET,
.prediv_mask = 0x1F800,
.prediv_offset = 11,
.prediv_val = 3,
@@ -356,6 +561,11 @@ struct mxc_dvfsper_data dvfs_per_data = {
.lp_low = 1200000,
};
+struct fec_platform_data fec_data = {
+ .phy = PHY_INTERFACE_MODE_MII,
+ .phy_mask = ~1UL,
+};
+
struct platform_pwm_backlight_data mxc_pwm_backlight_data = {
.pwm_id = 0,
.max_brightness = 255,
@@ -364,90 +574,649 @@ struct platform_pwm_backlight_data mxc_pwm_backlight_data = {
};
struct mxc_audio_platform_data wm8753_data = {
- .ssi_num = 1,
- .src_port = 2,
- .ext_port = 3,
- .sysclk = 12000000,
+ .ssi_num = 1,
+ .src_port = 2,
+ .ext_port = 3,
+ .sysclk = 0 /* Set on the fly */,
};
-struct mxc_fb_platform_data mx51_fb_data[] = {
- /*VGA*/
+struct mxc_fb_platform_data mx51_fb_data[2] = {
+ /* DISP0 */
{
- .interface_pix_fmt = IPU_PIX_FMT_RGB24,
- .mode_str = "1024x768M-16@60", /* Default */
+ .interface_pix_fmt = VIDEO_PIX_FMT,
+ .mode_str = "1024x768M-16@60", /* Default */
+ },
+ /* DISP1 */
+ {
+ .interface_pix_fmt = IPU_PIX_FMT_RGB666,
+ .mode_str = "800x480-16@60", /* Default */
}
};
-#if defined(CONFIG_UIO_PDRV_GENIRQ) || defined(CONFIG_UIO_PDRV_GENIRQ_MODULE)
-struct uio_info gpu2d_platform_data = {
- .name = "imx_gpu2d",
- .version = "1",
- .irq = MXC_INT_GPU2_IRQ,
- .open = gpu2d_open,
- .release = gpu2d_release,
- .mmap = gpu2d_mmap,
-};
+
+#if defined(CONFIG_KEYBOARD_GPIO)
+
+#define GPIO_BUTTON(gpio_num, ev_type, ev_code, act_low, descr) \
+{ \
+ .gpio = gpio_num, \
+ .type = ev_type, \
+ .code = ev_code, \
+ .active_low = act_low, \
+ .desc = "btn " descr, \
+}
+
+#define GPIO_BUTTON_LOW(gpio_num, event_code, description) \
+ GPIO_BUTTON(gpio_num, EV_KEY, event_code, 1, description)
+
+// user key 1
+#if defined(CONFIG_JSCCWMX51_V2)
+#define USER_KEY2_GPIO_NR 70
+#else
+#define USER_KEY2_GPIO_NR 8
#endif
+// user key 2
+#define USER_KEY1_GPIO_NR 1
+
+static struct gpio_keys_button ccwmx51js_gpio_keys[] = {
+ GPIO_BUTTON_LOW(USER_KEY1_GPIO_NR, KEY_MENU, "menu"),
+ GPIO_BUTTON_LOW(USER_KEY2_GPIO_NR, KEY_HOME, "home"),
+};
+
+
+struct gpio_keys_platform_data ccwmx51js_gpio_key_info = {
+ .buttons = ccwmx51js_gpio_keys,
+ .nbuttons = ARRAY_SIZE(ccwmx51js_gpio_keys),
+};
+
+struct platform_device ccwmx51js_keys_gpio = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &ccwmx51js_gpio_key_info,
+ },
+};
+#endif // KEYBOARD_GPIO
#if defined(CONFIG_FB_MXC_SYNC_PANEL) || defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE)
-struct ccwmx51_lcd_pdata * plcd_platform_data;
+struct ccwmx51_lcd_pdata plcd_platform_data[2];
+
+#if defined(CONFIG_VIDEO_AD9389) || defined(CONFIG_VIDEO_AD9389_MODULE)
+static u32 ccwmx51_get_max_video_pclk(void)
+{
+ /**
+ * TODO get this value from the clock subsystem.
+ * 133MHz seems to cause problems with the ext clk.
+ */
+ return KHZ2PICOS(132000);
+}
+#endif
+
+#if defined(CONFIG_CCWMX51_DISP1)
+static char *video2_options[FB_MAX] __read_mostly;
+static int ofonly2 __read_mostly;
+
+int fb2_get_options(char *name, char **option)
+{
+ char *opt, *options = NULL;
+ int opt_len, retval = 0;
+ int name_len = strlen(name), i;
+
+ if (name_len && ofonly2 && strncmp(name, "offb", 4))
+ retval = 1;
+
+ if (name_len && !retval) {
+ for (i = 0; i < FB_MAX; i++) {
+ if (video2_options[i] == NULL)
+ continue;
+ opt_len = strlen(video2_options[i]);
+ if (!opt_len)
+ continue;
+ opt = video2_options[i];
+ if (!strncmp(name, opt, name_len) &&
+ opt[name_len] == ':')
+ options = opt + name_len + 1;
+ }
+ }
+ if (options && !strncmp(options, "off", 3))
+ retval = 1;
+
+ if (option)
+ *option = options;
+
+ return retval;
+}
+
+static int __init video2_setup(char *options)
+{
+ int i, global = 0;
+
+ if (!options || !*options)
+ global = 1;
+
+ if (!global && !strncmp(options, "ofonly", 6)) {
+ ofonly2 = 1;
+ global = 1;
+ }
-struct ccwmx51_lcd_pdata * ccwmx51_get_display(char *name)
+ if (!global && !strstr(options, "fb:")) {
+ fb_mode_option = options;
+ global = 1;
+ }
+
+ if (!global) {
+ for (i = 0; i < FB_MAX; i++) {
+ if (video2_options[i] == NULL) {
+ video2_options[i] = options;
+ break;
+ }
+ }
+ }
+
+ return 1;
+}
+__setup("video2=", video2_setup);
+#endif /* defined(CONFIG_CCWMX51_DISP1) */
+
+struct ccwmx51_lcd_pdata * ccwmx51_find_video_config(struct ccwmx51_lcd_pdata list[],
+ int len,
+ const char *name)
{
-#if defined(CONFIG_CCWMX51_LQ070Y3DG3B) || defined(CONFIG_CCWMX51_CUSTOM)
int i;
- for (i = 0; i < ARRAY_SIZE(lcd_display_list); i++)
- if (!strncmp(lcd_display_list[i].fb_pdata.mode->name,
- name, strlen(lcd_display_list[i].fb_pdata.mode->name)))
- return &lcd_display_list[i];
+ for (i = 0; i < len; i++)
+ if (!strncmp(list[i].fb_pdata.mode->name,
+ name, strlen(list[i].fb_pdata.mode->name)))
+ return &list[i];
+ return NULL;
+}
+
+static char *ccwmx51_get_video_cmdline_opt(int dispif, const char *str)
+{
+ char *options = NULL;
+ int ret = 1;
+ int len = strlen(str);
+
+#if defined(CONFIG_CCWMX51_DISP0)
+ if (dispif == 0) {
+ ret = fb_get_options("displayfb", &options);
+ }
#endif
+#if defined(CONFIG_CCWMX51_DISP1)
+ if (dispif == 1) {
+ ret = fb2_get_options("displayfb", &options);
+ }
+#endif
+ if (ret || !options)
+ return NULL;
+ if (!len || !strncasecmp(options, str, len))
+ return &options[len];
+
return NULL;
}
-int __init ccwmx51_init_fb(void)
+#if defined(CONFIG_VIDEO_AD9389) || defined(CONFIG_VIDEO_AD9389_MODULE)
+static void fb_dump_mode(const char *str, const struct fb_videomode *vm)
+{
+ if (!(debug & AD9389_DBG))
+ return;
+ if (vm == NULL)
+ return;
+
+ printk(KERN_INFO "%s geometry %u %u %u\n",
+ str, vm->xres, vm->yres, vm->pixclock);
+ printk(KERN_INFO "%s timings %u %u %u %u %u %u %u\n", str, vm->pixclock, vm->left_margin,
+ vm->right_margin, vm->upper_margin, vm->lower_margin, vm->hsync_len, vm->vsync_len);
+ printk(KERN_INFO "%s flag %u sync %u vmode %u %s\n", str, vm->flag, vm->sync, vm->vmode,
+ vm->flag & FB_MODE_IS_FIRST ? "preferred" : "");
+}
+
+static void fb_dump_var(const char *str, struct fb_var_screeninfo *var)
{
- char *options = NULL, *p;
+ if (!(debug & AD9389_DBG))
+ return;
+ if (var == NULL)
+ return;
- if (fb_get_options("displayfb", &options))
- pr_warning("no display information available in command line\n");
+ printk(KERN_INFO "%s geometry %u %u %u %u\n",
+ str, var->xres, var->yres, var->xres_virtual, var->yres_virtual);
+ printk(KERN_INFO "%s offset %u %u %u %u %u\n",
+ str, var->xoffset, var->yoffset, var->height, var->width, var->bits_per_pixel);
+ printk(KERN_INFO "%s timings %u %u %u %u %u %u %u\n",
+ str, var->pixclock, var->left_margin, var->right_margin,
+ var->upper_margin, var->lower_margin, var->hsync_len, var->vsync_len);
+ printk(KERN_INFO "%s accel_flags %u sync %u vmode %u\n",
+ str, var->accel_flags, var->sync, var->vmode);
+ printk(KERN_INFO "%d bpp\n", var->bits_per_pixel);
+}
- if (!options)
- return -ENODEV;
+enum hdmi_mode get_hdmi_mode(struct ad9389_dev *ad9389, struct fb_videomode **vm, char **str, unsigned int *vpclk, int *ext_clk)
+{
+ struct ad9389_pdata *pdata = ad9389->client->dev.platform_data;
+ struct ccwmx51_lcd_pdata *panel;
+ char *p, *temp;
- if (!strncasecmp(options, "VGA", 3)) {
- pr_info("VGA interface is primary\n");
+ if ((p = ccwmx51_get_video_cmdline_opt(pdata->dispif, "HDMI")) != NULL) {
+ DBG(AD9389_DBG, "HDMI: %s config on DISP%d\n", p, pdata->dispif);
/* 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 */
+ if (vpclk != NULL ) {
+ *vpclk = 0;
+ /* Parse pclk, it was passed through cmdline */
+ if ((temp = strstr(p, "pclk=")) != NULL) {
+ *vpclk = (unsigned int)simple_strtoul(temp + 5, NULL, 10);
+ if (*vpclk < ccwmx51_get_max_video_pclk())
+ *vpclk = 0;
+ }
+ DBG(AD9389_DBG, "HDMI: using cmdline pclk %d\n", *vpclk);
+ }
+ if (ext_clk != NULL ) {
+ /* For single display, default is internal clk and can be overrided by cmdline */
+#if !defined(CONFIG_CCWMX51_DISP0) || !defined(CONFIG_CCWMX51_DISP1)
+ *ext_clk = 1;
+#else
+ *ext_clk = 0;
+#endif
+ /* Parse ext_clk, it was passed through cmdline */
+ if ((temp = strstr(p, "int_clk")) != NULL)
+ *ext_clk = 0;
+ if ((temp = strstr(p, "ext_clk")) != NULL)
+ *ext_clk = 1;
+ DBG(AD9389_DBG, "HDMI: using %s\n", ext_clk ? "ext_clk" : "int_clk");
+ }
+ if (*p++ != '@') {
+ pr_info("Video resolution for HDMI interface not provided, using auto\n");
+ return MODE_AUTO;
+ } else if (!strncasecmp(p, "auto@", 5)) {
+ *str = p + 5;
+ if ((temp = strchr(*str, ',')) != NULL)
+ *temp = '\0';
+ DBG(AD9389_DBG, "HDMI: auto string %s\n", *str);
+ return MODE_AUTO_STRING;
+ } else if (!strncasecmp(p, "auto", 4)) {
+ DBG(AD9389_DBG, "HDMI: auto\n");
+ return MODE_AUTO;
+ } else if ((panel = ccwmx51_find_video_config(ad9389_panel_list,
+ ARRAY_SIZE(ad9389_panel_list),
+ p)) != NULL) {
+ *vm = panel->fb_pdata.mode;
+ memcpy(&mx51_fb_data[pdata->dispif],
+ &plcd_platform_data[pdata->dispif].fb_pdata,
+ sizeof(struct mxc_fb_platform_data));
+ DBG(AD9389_DBG, "HDMI: forced mode\n");
+ return MODE_FORCED;
} else {
- options = &options[4];
- if (((p = strsep (&options, "@")) != NULL) && *p) {
- if (!strcmp(p, "640x480x16")) {
- strcpy(mx51_fb_data[0].mode_str, "640x480M-16@60");
- } else if (!strcmp(p, "800x600x16")) {
- strcpy(mx51_fb_data[0].mode_str, "800x600M-16@60");
- } else if (!strcmp(p, "1024x768x16")) {
- strcpy(mx51_fb_data[0].mode_str, "1024x768M-16@60");
- } else if (!strcmp(p, "1280x1024x16")) {
- strcpy(mx51_fb_data[0].mode_str, "1280x1024M-16@60");
- } else
- pr_warning("Unsuported video resolution: %s, using default\n", p);
+ *str = p;
+ if ((temp = strchr(*str, ',')) != NULL)
+ *temp = '\0';
+ DBG(AD9389_DBG, "HDMI: string %s\n", *str);
+ return MODE_STRING;
+ }
+ }
+ return MODE_UNKNOWN;
+}
+
+#define AD9389_STR_LEN 30
+static void mxc_videomode_to_var(struct ad9389_dev *ad9389, struct fb_var_screeninfo *var)
+{
+ struct fb_info *info = ad9389->fbi;
+ const struct fb_videomode *fbvmode = NULL;
+ char *modestr = NULL, str[AD9389_STR_LEN];
+ unsigned int tpclk;
+ int modeidx, ext_clk;
+ enum hdmi_mode mode;
+
+ var->bits_per_pixel = CONFIG_CCWMX51_DEFAULT_VIDEO_BPP; /* Set default bpp */
+ /* First, check if we have a predefined mode through the kernel command line */
+ mode = get_hdmi_mode(ad9389, (struct fb_videomode **)&fbvmode, &modestr, &tpclk, &ext_clk);
+ if (mode == MODE_AUTO) {
+ /* auto, or no video mode provided */
+ strncpy(str, "HDMI auto selected mode:", AD9389_STR_LEN - 1);
+ fbvmode = fb_find_best_mode(var, &info->modelist);
+ if (!fbvmode) {
+ fbvmode = fb_find_best_display(&info->monspecs, &info->modelist);
+ if (!fbvmode) {
+ printk(KERN_WARNING
+ "HDMI: unable to find a valid video mode/screen,"
+ " try forcing a mode\n");
+ /* Use default... */
+ fbvmode = &ad9389_1024x768x24;
+ strncpy(str, "HDMI default mode:", AD9389_STR_LEN - 1);
}
}
- } else {
- if ((plcd_platform_data = ccwmx51_get_display(options)) != NULL) {
- memcpy(&mx51_fb_data[0], &plcd_platform_data->fb_pdata, sizeof(struct mxc_fb_platform_data));
- plcd_platform_data->vif = 0; /* Select video interface 0 */
+ } else if (mode == MODE_FORCED) {
+ /* Selected video mode through cmd line parameters provided */
+ strncpy(str, "HDMI forced mode:", AD9389_STR_LEN - 1);
+ } else if ((mode == MODE_STRING || mode == MODE_AUTO_STRING) && modestr) {
+ DBG(AD9389_DBG, "HDMI mode string: %s\n", modestr);
+ modeidx = fb_find_mode(var, info, modestr,
+ info->monspecs.modedb,
+ info->monspecs.modedb_len,
+ NULL, var->bits_per_pixel);
+ if (!(modeidx == 1 || modeidx == 1)) {
+ DBG(AD9389_DBG, "HDMI: unable to find valid mode (%s)\n", modestr);
+ return;
}
+ strncpy(str, "HDMI string mode:", AD9389_STR_LEN - 1);
+ }
+ str[AD9389_STR_LEN - 1] = 0;
+ if ((mode == MODE_AUTO) || (mode == MODE_FORCED)) {
+ fb_dump_mode(str, fbvmode);
+ fb_videomode_to_var(var, fbvmode);
}
+
+ if (ext_clk)
+ var->sync |= FB_SYNC_EXT;
+
+ /* Check if clock must be readjusted */
+ if (tpclk != 0)
+ var->pixclock = tpclk;
+
+ fb_dump_var(str, var);
+}
+
+/**
+ * This function parses the list of supported video modes (got from fb_edid_to_monspecs) and
+ * filters out not supported configurations
+ */
+static void mxcfb_vmode_to_modelist(struct fb_videomode *modedb, int num,
+ struct list_head *head, struct fb_var_screeninfo *var)
+{
+ int i, xres = 0, yres = 0, aspratio = 0;
+
+ INIT_LIST_HEAD(head);
+
+ /**
+ * Add the modes we got through the monitor specs, filtering out those
+ * unsupported configurations.
+ */
+ for (i = 0; i < num; i++) {
+ struct list_head *pos, *n;
+ struct fb_modelist *modelist;
+ int remove, vmaspratio;
+
+ remove = 0;
+ vmaspratio = -1;
+
+ /* Use the preferred mode to compute the aspect ratio */
+ if (modedb[i].flag & FB_MODE_IS_FIRST) {
+ DBG(AD9389_DBG, "PREFERRED: %ux%u%s%u pclk=%u\n",
+ modedb[i].xres, modedb[i].yres,
+ (modedb[i].vmode & FB_VMODE_INTERLACED ) ? "i@" : "@",
+ modedb[i].refresh, modedb[i].pixclock);
+
+ aspratio = modedb[i].xres * 10 / modedb[i].yres;
+ DBG(AD9389_DBG, "Aspect Ratio: %d\n", aspratio);
+ }
+
+ if (modedb[i].yres)
+ vmaspratio = modedb[i].xres * 10 / modedb[i].yres;
+
+ if (vmaspratio != aspratio) {
+ DBG(AD9389_DBG, "REMOVED: %ux%u%s%u pclk=%u (aspect ratio)\n",
+ modedb[i].xres, modedb[i].yres,
+ (modedb[i].vmode & FB_VMODE_INTERLACED ) ? "i@" : "@",
+ modedb[i].refresh, modedb[i].pixclock);
+ continue;
+ }
+
+ /* Interlaced not supported */
+ if (modedb[i].vmode & FB_VMODE_INTERLACED) {
+ DBG(AD9389_DBG, "REMOVED: %ux%u%s%u pclk=%u (interlaced modes not supported)\n",
+ modedb[i].xres, modedb[i].yres,
+ (modedb[i].vmode & FB_VMODE_INTERLACED ) ? "i@" : "@",
+ modedb[i].refresh, modedb[i].pixclock);
+ continue;
+ }
+
+ /* If clock exceeds the max pixel clock supported, remove that video mode */
+ if ((modedb[i].pixclock * 115 / 100) < ccwmx51_get_max_video_pclk()) {
+ DBG(AD9389_DBG, "REMOVED: %ux%u%s%u pclk=%u (exceed %u limit)\n",
+ modedb[i].xres, modedb[i].yres,
+ (modedb[i].vmode & FB_VMODE_INTERLACED ) ? "i@" : "@",
+ modedb[i].refresh, modedb[i].pixclock, ccwmx51_get_max_video_pclk());
+ continue;
+ }
+
+ /* If over the pixel clock limix, but close enough, set the max pixel clock freq */
+ if (modedb[i].pixclock < ccwmx51_get_max_video_pclk())
+ modedb[i].pixclock = ccwmx51_get_max_video_pclk();
+
+ /**
+ * Adjust timing to IPU restrictions (better done here, to avoid ipu driver to
+ * incorrectly calculate settings based on our configuration).
+ */
+ if (modedb[i].lower_margin < 2) {
+ /* This will not affect much, so we dont adjust the pixel clock */
+ DBG(AD9389_DBG, "ADJUSTED: lower margin from %u to 2\n",
+ modedb[i].lower_margin);
+ modedb[i].lower_margin = 2;
+ }
+
+ /**
+ * Remove duplicated modes, selecting the best modes accordingly to the
+ * platform video constraints.
+ */
+ list_for_each_safe(pos, n, head) {
+ modelist = list_entry(pos, struct fb_modelist, list);
+
+ if ((modelist->mode.xres == modedb[i].xres) &&
+ (modelist->mode.yres == modedb[i].yres)) {
+
+ if (modedb[i].pixclock == ccwmx51_get_max_video_pclk()) {
+ /* If current mode pixclk is set to max clock, do not
+ * add this mode and use the existing one. */
+ remove = 1;
+ } else if ((modelist->mode.refresh == modedb[i].refresh) &&
+ (modedb[i].flag & FB_MODE_IS_DETAILED)) {
+ DBG(AD9389_DBG, "REMOVED: %ux%u%s%u pclk=%u (duplicated)\n",
+ modelist->mode.xres, modelist->mode.yres,
+ (modelist->mode.vmode & FB_VMODE_INTERLACED ) ? "i@" : "@",
+ modelist->mode.refresh, modelist->mode.pixclock);
+ list_del(pos);
+ kfree(pos);
+ } else {
+ /* Do not add this mode, it is not a detailed timing */
+ remove = 1;
+ }
+ }
+ }
+
+ if (!remove) {
+ fb_add_videomode(&modedb[i], head);
+ DBG(AD9389_DBG, "ADDING: Video mode %ux%u%s%u pclk=%u, %s detailed\n",
+ modedb[i].xres, modedb[i].yres,
+ (modedb[i].vmode & FB_VMODE_INTERLACED ) ? "i@" : "@",
+ modedb[i].refresh, modedb[i].pixclock,
+ (modedb[i].flag & FB_MODE_IS_DETAILED) ? "" : "no");
+
+ if (modedb[i].xres > xres && modedb[i].yres > yres) {
+ xres = modedb[i].xres;
+ yres = modedb[i].yres;
+ }
+ }
+ }
+
+ /* Update var->xres and var->yres, used to determine the best video mode*/
+ if (var->xres != xres || var->yres != yres) {
+ var->xres = xres;
+ var->yres = yres;
+ }
+}
+
+static int ccwmx51_hdmi_hw_init(struct ad9389_dev *ad9389)
+{
+ struct ad9389_pdata *pdata = ad9389->client->dev.platform_data;
+
+ if (pdata->dispif == 0) {
+ mxc_request_iomux(AD9389_GPIO_IRQ, IOMUX_CONFIG_GPIO | IOMUX_CONFIG_SION);
+ mxc_iomux_set_pad(AD9389_GPIO_IRQ, PAD_CTL_SRE_SLOW | PAD_CTL_DRV_MEDIUM |
+ PAD_CTL_100K_PU | PAD_CTL_HYS_ENABLE |
+ PAD_CTL_DRV_VOT_HIGH);
+
+ gpio_request(IOMUX_TO_GPIO(AD9389_GPIO_IRQ), "ad9389_irq");
+ gpio_direction_input(IOMUX_TO_GPIO(AD9389_GPIO_IRQ));
+
+ set_irq_type(IOMUX_TO_GPIO(AD9389_GPIO_IRQ), IRQ_TYPE_EDGE_BOTH);
+ }
+
+ /* Configure here the hot plug detection for HDMI on DISP1 */
+ /* if (pdata->dispif == 1) { } */
+
+ gpio_video_active(pdata->dispif,
+ PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST);
+
return 0;
}
-device_initcall(ccwmx51_init_fb);
+
+static void ccwmx51_hdmi_disp_connected(struct ad9389_dev *ad9389)
+{
+ printk(KERN_DEBUG "%s: display connected\n", __func__);
+}
+
+static void ccwmx51_hdmi_disp_disconnected(struct ad9389_dev *ad9389)
+{
+ printk(KERN_DEBUG "%s: display disconnected\n", __func__);
+}
+
+static struct ad9389_pdata hdmi_pdata = {
+ .hw_init = &ccwmx51_hdmi_hw_init,
+ .disp_connected = &ccwmx51_hdmi_disp_connected,
+ .disp_disconnected = &ccwmx51_hdmi_disp_disconnected,
+ .vmode_to_modelist = &mxcfb_vmode_to_modelist,
+ .vmode_to_var = &mxc_videomode_to_var,
+ .edid_addr = (0x7e >> 1),
+ .dispif = 0,
+};
+
+struct i2c_board_info ccwmx51_hdmi[] __initdata = {
+ {
+ I2C_BOARD_INFO("ad9389", 0x39),
+ .irq = IOMUX_TO_IRQ(AD9389_GPIO_IRQ),
+ .platform_data = &hdmi_pdata,
+ },
+};
+#endif
+
+#define MAX_VIDEO_IF 2
+int __init ccwmx51_init_fb(void)
+{
+ struct ccwmx51_lcd_pdata *panel;
+ char *p, *mstr;
+ int i;
+
+ plcd_platform_data[0].vif = -1;
+ plcd_platform_data[1].vif = -1;
+
+ for (i = 0; i < MAX_VIDEO_IF; i++) {
+#if !defined(CONFIG_CCWMX51_DISP0)
+ if (i == 0) continue;
+#endif
+#if !defined(CONFIG_CCWMX51_DISP1)
+ if (i == 1) continue;
+#endif
+ if ((p = ccwmx51_get_video_cmdline_opt(i, "HDMI")) != NULL) {
+#if defined(CONFIG_VIDEO_AD9389) || defined(CONFIG_VIDEO_AD9389_MODULE)
+ pr_info("HDMI interface in DISP%d\n", i);
+ i2c_register_board_info(1, ccwmx51_hdmi, 1);
+#else
+ pr_info("HDMI selected in DISP%d, but driver unavailable\n", i);
+ continue;
+#endif
+ } else if ((p = ccwmx51_get_video_cmdline_opt(i, "LCD")) != NULL) {
+ pr_info("LCD interface in DISP%d", i);
+ if (*p++ != '@') {
+ pr_info("Panel not provided, video interface will be disabled\n");
+ continue;
+ }
+ if ((panel = ccwmx51_find_video_config(lcd_panel_list,
+ ARRAY_SIZE(lcd_panel_list),
+ p)) != NULL) {
+ pr_info("Panel: %s", p);
+ memcpy(&plcd_platform_data[i],
+ panel,
+ sizeof(struct ccwmx51_lcd_pdata));
+ memcpy(&mx51_fb_data[i],
+ &plcd_platform_data[i].fb_pdata,
+ sizeof(struct mxc_fb_platform_data));
+ plcd_platform_data[i].vif = i;
+ mxc_register_device(&lcd_pdev[i], (void *)&plcd_platform_data[i]);
+ }
+ } else if ((p = ccwmx51_get_video_cmdline_opt(i, "VGA")) != NULL) {
+ pr_info("VGA interface in DISP%d\n", i);
+ gpio_video_active(i, PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST);
+ mstr = p - 3;
+
+ /* Get the desired configuration provided by the bootloader */
+ if (*p++ != '@') {
+ pr_info("Video resolution for VGA interface not provided, using default\n");
+ } else {
+ /* Check string to see if its one of the configurations we alaredy have...
+ * and if not, pass it as mode string, just in case we want to use one
+ * of the standard video configurations
+ */
+ if ((panel = ccwmx51_find_video_config(vga_panel_list,
+ ARRAY_SIZE(vga_panel_list),
+ p)) != NULL) {
+ pr_info("Panel: %s", p);
+ memcpy(&mx51_fb_data[i],
+ &plcd_platform_data[i].fb_pdata,
+ sizeof(struct mxc_fb_platform_data));
+ } else {
+ /* Pass the video configuration as mode string */
+ pr_info("VGA: string %s", p);
+
+ if (!strcmp(p, "800x600")) {
+ strcpy(mx51_fb_data[0].mode_str, "VGA@800x600M-32");
+ } else if (!strcmp(p, "1280x1024")) {
+ strcpy(mx51_fb_data[0].mode_str, "VGA@1280x1024M-32");
+ } else {
+ strcpy(mx51_fb_data[0].mode_str, mstr);
+ }
+ }
+ }
+ }
+ mxc_fb_devices[i].num_resources = 1;
+ mxc_fb_devices[i].resource = &mxcfb_resources[i];
+ mxc_register_device(&mxc_fb_devices[i], &mx51_fb_data[i]);
+ }
+
+ /* DI0/1 DP-FG channel, used by the VPU */
+ mxc_register_device(&mxc_fb_devices[2], NULL);
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_PATA_FSL) || defined(CONFIG_PATA_FSL_MODULE)
+extern void gpio_ata_active(void);
+extern void gpio_ata_inactive(void);
+
+static int ccwmx51_init_ata(struct platform_device *pdev)
+{
+ gpio_ata_active();
+ return 0;
+}
+
+static void ccwmx51_deinit_ata(void)
+{
+ gpio_ata_inactive();
+}
+
+struct fsl_ata_platform_data ata_data = {
+#ifndef CONFIG_PATA_FSL_DISABLE_DMA
+ .udma_mask = ATA_UDMA3,
+ .mwdma_mask = ATA_MWDMA2,
+#endif
+ .pio_mask = ATA_PIO4,
+ .fifo_alarm = MXC_IDE_DMA_WATERMARK / 2,
+ .max_sg = MXC_IDE_DMA_BD_NR,
+ .init = ccwmx51_init_ata,
+ .exit = ccwmx51_deinit_ata,
+ .core_reg = NULL,
+ .io_reg = NULL,
+};
#endif
-void __init ccwmx51_init_devices ( void )
+void ccwmx51_init_devices(void)
{
#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
ccwmx51_init_ext_eth_mac();
diff --git a/arch/arm/mach-mx5/devices_ccwmx51.h b/arch/arm/mach-mx5/devices_ccwmx51.h
index 7208099b6e2d..6e53be44a5f5 100644
--- a/arch/arm/mach-mx5/devices_ccwmx51.h
+++ b/arch/arm/mach-mx5/devices_ccwmx51.h
@@ -28,17 +28,29 @@ extern struct mxc_w1_config mxc_w1_data;
extern struct mxc_spdif_platform_data mxc_spdif_data;
extern struct tve_platform_data tve_data;
extern struct mxc_dvfs_platform_data dvfs_core_data;
+extern struct fec_platform_data fec_data;
extern struct mxc_dvfsper_data dvfs_per_data;
extern struct platform_pwm_backlight_data mxc_pwm_backlight_data;
extern struct mxc_audio_platform_data wm8753_data;
extern struct mxc_fb_platform_data mx51_fb_data[];
extern struct uio_info gpu2d_platform_data;
-extern struct ccwmx51_lcd_pdata * plcd_platform_data;
+extern struct ccwmx51_lcd_pdata plcd_platform_data[2];
+extern struct fsl_ata_platform_data ata_data;
extern int __init ccwmx51_init_i2c2(void);
extern void ccwmx51_init_spidevices(void);
extern int __init ccwmx51_init_fb(void);
extern void __init ccwmx51_io_init(void);
extern int __init ccwmx51_init_mc13892(void);
extern struct platform_device smsc911x_device;
+extern void ccwmx51_set_mod_variant(u8 variant);
+extern void ccwmx51_set_mod_revision(u8 revision);
+extern void ccwmx51_set_mod_sn(u32 sn);
+extern void ccwmx51_register_sdio(int interface);
+extern void ccwmx51_init_devices(void);
+extern int ccwmx51_create_sysfs_entries(void);
+extern struct gpio_keys_platform_data ccwmx51js_gpio_key_info;
+extern void ccwmx51_init_devices(void);
+extern int ccwmx51_create_sysfs_entries(void);
+
#endif /* DEVICES_CCWMX51_H_ */
diff --git a/arch/arm/mach-mx5/displays/displays.h b/arch/arm/mach-mx5/displays/displays.h
index 1fa2c1d05b5d..d738781a31e2 100644
--- a/arch/arm/mach-mx5/displays/displays.h
+++ b/arch/arm/mach-mx5/displays/displays.h
@@ -1,7 +1,7 @@
/*
- * arch/arm/mach-s3c2443/displays/displays.h
+ * arch/arm/mach-mx5/displays/displays.h
*
- * Copyright (C) 2009 by Digi International Inc.
+ * Copyright (C) 2009-2010 by Digi International Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
@@ -12,20 +12,17 @@
#ifndef __ASM_ARCH_MXC_CCWMX51_DISPLAYS_H__
#define __ASM_ARCH_MXC_CCWMX51_DISPLAYS_H__
-#if defined(CONFIG_CCWMX51_LQ070Y3DG3B)
-#include "LQ070Y3DG3B.h"
-#endif
-#if defined(CONFIG_CCWMX51_CUSTOM)
-#include "CUSTOM.h"
-#endif
+extern void gpio_video_active(int vif, u32 pad);
+extern void gpio_video_inactive(int vif);
-struct ccwmx51_lcd_pdata lcd_display_list[] = {
-#if defined(CONFIG_CCWMX51_LQ070Y3DG3B)
- LQ070Y3DG3B_DISPLAY,
+#ifdef CONFIG_CCWMX51_DISP0_RGB888
+#define VIDEO_PIX_FMT IPU_PIX_FMT_RGB24
+#else
+#define VIDEO_PIX_FMT IPU_PIX_FMT_RGB666
#endif
-#if defined(CONFIG_CCWMX51_CUSTOM)
- CUSTOM_DISPLAY,
-#endif
-};
+
+#include "hdmi_ad9389.h"
+#include "vga.h"
+#include "lcd.h"
#endif /* __ASM_ARCH_MXC_CCWMX51_DISPLAYS_H__ */
diff --git a/arch/arm/mach-mx5/dma.c b/arch/arm/mach-mx5/dma.c
index b79fab73e41f..39b7776c6d15 100644
--- a/arch/arm/mach-mx5/dma.c
+++ b/arch/arm/mach-mx5/dma.c
@@ -13,11 +13,14 @@
#include <linux/init.h>
#include <linux/device.h>
#include <asm/dma.h>
+#include <mach/dma.h>
#include <mach/hardware.h>
+#include <mach/mxc_uart.h>
#include "serial.h"
#include "sdma_script_code.h"
#include "sdma_script_code_mx53.h"
+#include "sdma_script_code_mx50.h"
#define MXC_MMC_BUFFER_ACCESS 0x20
#define MXC_SDHC_MMC_WML 64
@@ -1344,16 +1347,82 @@ static void __init mx53_sdma_get_script_info(sdma_script_start_addrs *sdma_scrip
sdma_script_addr->mxc_sdma_dptc_dvfs_addr = -1;
/* core */
- sdma_script_addr->mxc_sdma_start_addr = (unsigned short *)sdma_code;
+ sdma_script_addr->mxc_sdma_start_addr = (unsigned short *)sdma_code_mx53;
sdma_script_addr->mxc_sdma_ram_code_start_addr = RAM_CODE_START_ADDR_MX53;
sdma_script_addr->mxc_sdma_ram_code_size = RAM_CODE_SIZE_MX53;
}
+static void __init mx50_sdma_get_script_info(sdma_script_start_addrs *sdma_script_addr)
+{
+ /* AP<->BP */
+ sdma_script_addr->mxc_sdma_ap_2_ap_addr = ap_2_ap_ADDR_MX50;
+ sdma_script_addr->mxc_sdma_ap_2_bp_addr = -1;
+ sdma_script_addr->mxc_sdma_bp_2_ap_addr = -1;
+ sdma_script_addr->mxc_sdma_ap_2_ap_fixed_addr = -1;
+
+ /*misc */
+ sdma_script_addr->mxc_sdma_loopback_on_dsp_side_addr = -1;
+ sdma_script_addr->mxc_sdma_mcu_interrupt_only_addr = -1;
+
+ /* firi */
+ sdma_script_addr->mxc_sdma_firi_2_per_addr = -1;
+ sdma_script_addr->mxc_sdma_firi_2_mcu_addr = -1;
+ sdma_script_addr->mxc_sdma_per_2_firi_addr = -1;
+ sdma_script_addr->mxc_sdma_mcu_2_firi_addr = -1;
+
+ /* uart */
+ sdma_script_addr->mxc_sdma_uart_2_per_addr = uart_2_mcu_ADDR_MX50;
+ sdma_script_addr->mxc_sdma_uart_2_mcu_addr = uart_2_mcu_ADDR_MX50;
+
+ /* UART SH */
+ sdma_script_addr->mxc_sdma_uartsh_2_per_addr = uartsh_2_mcu_ADDR_MX50;
+ sdma_script_addr->mxc_sdma_uartsh_2_mcu_addr = uartsh_2_mcu_ADDR_MX50;
+
+ /* SHP */
+ sdma_script_addr->mxc_sdma_per_2_shp_addr = mcu_2_shp_ADDR_MX50;
+ sdma_script_addr->mxc_sdma_shp_2_per_addr = shp_2_mcu_ADDR_MX50;
+ sdma_script_addr->mxc_sdma_mcu_2_shp_addr = mcu_2_shp_ADDR_MX50;
+ sdma_script_addr->mxc_sdma_shp_2_mcu_addr = shp_2_mcu_ADDR_MX50;
+
+ /* ATA use it's own DMA */
+ sdma_script_addr->mxc_sdma_mcu_2_ata_addr = -1;
+ sdma_script_addr->mxc_sdma_ata_2_mcu_addr = -1;
+
+ /* app */
+ sdma_script_addr->mxc_sdma_app_2_per_addr = app_2_mcu_ADDR_MX50;
+ sdma_script_addr->mxc_sdma_app_2_mcu_addr = app_2_mcu_ADDR_MX50;
+ sdma_script_addr->mxc_sdma_per_2_app_addr = mcu_2_app_ADDR_MX50;
+ sdma_script_addr->mxc_sdma_mcu_2_app_addr = mcu_2_app_ADDR_MX50;
+
+ /* MSHC */
+ sdma_script_addr->mxc_sdma_mshc_2_mcu_addr = -1;
+ sdma_script_addr->mxc_sdma_mcu_2_mshc_addr = -1;
+
+ /* spdif */
+ sdma_script_addr->mxc_sdma_spdif_2_mcu_addr = -1;
+ sdma_script_addr->mxc_sdma_mcu_2_spdif_addr = -1;
+
+ sdma_script_addr->mxc_sdma_asrc_2_mcu_addr = -1;
+
+ /* IPU */
+ sdma_script_addr->mxc_sdma_ext_mem_2_ipu_addr = -1;
+
+ /* DVFS */
+ sdma_script_addr->mxc_sdma_dptc_dvfs_addr = -1;
+
+ /* core */
+ sdma_script_addr->mxc_sdma_start_addr = (unsigned short *)sdma_code_mx50;
+ sdma_script_addr->mxc_sdma_ram_code_start_addr = RAM_CODE_START_ADDR_MX50;
+ sdma_script_addr->mxc_sdma_ram_code_size = RAM_CODE_SIZE_MX50;
+}
+
void __init mxc_sdma_get_script_info(sdma_script_start_addrs *sdma_script_addr)
{
if (cpu_is_mx51())
mx51_sdma_get_script_info(sdma_script_addr);
- else
+ else if (cpu_is_mx53())
mx53_sdma_get_script_info(sdma_script_addr);
+ else
+ mx50_sdma_get_script_info(sdma_script_addr);
}
diff --git a/arch/arm/mach-mx5/dummy_gpio.c b/arch/arm/mach-mx5/dummy_gpio.c
index 8eb771d29a06..9d4cd07d28f9 100644
--- a/arch/arm/mach-mx5/dummy_gpio.c
+++ b/arch/arm/mach-mx5/dummy_gpio.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -53,12 +53,6 @@ EXPORT_SYMBOL(gpio_pmic_active);
void gpio_activate_audio_ports(void) {}
EXPORT_SYMBOL(gpio_activate_audio_ports);
-void gpio_sdhc_active(int module) {}
-EXPORT_SYMBOL(gpio_sdhc_active);
-
-void gpio_sdhc_inactive(int module) {}
-EXPORT_SYMBOL(gpio_sdhc_inactive);
-
void gpio_sensor_select(int sensor) {}
void gpio_sensor_active(unsigned int csi) {}
@@ -67,12 +61,6 @@ EXPORT_SYMBOL(gpio_sensor_active);
void gpio_sensor_inactive(unsigned int csi) {}
EXPORT_SYMBOL(gpio_sensor_inactive);
-void gpio_ata_active(void) {}
-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);
@@ -105,3 +93,9 @@ EXPORT_SYMBOL(gpio_spdif_active);
void gpio_spdif_inactive(void) {}
EXPORT_SYMBOL(gpio_spdif_inactive);
+
+void gpio_mlb_active(void) {}
+EXPORT_SYMBOL(gpio_mlb_active);
+
+void gpio_mlb_inactive(void) {}
+EXPORT_SYMBOL(gpio_mlb_inactive);
diff --git a/arch/arm/mach-mx5/iomux.c b/arch/arm/mach-mx5/iomux.c
index 319980ad176a..4cca66447443 100644
--- a/arch/arm/mach-mx5/iomux.c
+++ b/arch/arm/mach-mx5/iomux.c
@@ -37,6 +37,9 @@
#define INPUT_CTL_START_MX53 0x730
#define MUX_I_END_MX53 (PAD_I_START_MX53 - 4)
+#define PAD_I_START_MX50 0x2CC
+#define INPUT_CTL_START_MX50 0x6C4
+
/*!
* IOMUX register (base) addressesf
*/
@@ -52,8 +55,10 @@ static inline void *_get_sw_pad(void)
{
if (cpu_is_mx51())
return IO_ADDRESS(IOMUXC_BASE_ADDR) + PAD_I_START_MX51;
- else
+ else if (cpu_is_mx53())
return IO_ADDRESS(IOMUXC_BASE_ADDR) + PAD_I_START_MX53;
+ else
+ return IO_ADDRESS(IOMUXC_BASE_ADDR) + PAD_I_START_MX50;
}
static inline void * _get_mux_reg(iomux_pin_name_t pin)
@@ -102,6 +107,9 @@ static inline void * _get_pad_reg(iomux_pin_name_t pin)
static inline void * _get_mux_end(void)
{
+ if (cpu_is_mx50())
+ return IO_ADDRESS(IOMUXC_BASE_ADDR) + 0x2C8;
+
if (cpu_is_mx51_rev(CHIP_REV_2_0) < 0)
return(IO_ADDRESS(IOMUXC_BASE_ADDR) + (0x3F8 - 4));
else
@@ -264,8 +272,10 @@ void mxc_iomux_set_input(iomux_input_select_t input, u32 config)
reg = IOMUXSW_INPUT_CTL + (input << 2) + INPUT_CTL_START_MX51_TO1;
} else if (cpu_is_mx51()) {
reg = IOMUXSW_INPUT_CTL + (input << 2) + INPUT_CTL_START_MX51;
- } else
+ } else if (cpu_is_mx53()) {
reg = IOMUXSW_INPUT_CTL + (input << 2) + INPUT_CTL_START_MX53;
+ } else
+ reg = IOMUXSW_INPUT_CTL + (input << 2) + INPUT_CTL_START_MX50;
BUG_ON(input >= MUX_INPUT_NUM_MUX);
__raw_writel(config, reg);
diff --git a/arch/arm/mach-mx5/lpmodes.c b/arch/arm/mach-mx5/lpmodes.c
index 32af9ccc4f6a..c9d770231b54 100644
--- a/arch/arm/mach-mx5/lpmodes.c
+++ b/arch/arm/mach-mx5/lpmodes.c
@@ -37,7 +37,6 @@
#include <mach/clock.h>
#include <mach/hardware.h>
#include <linux/regulator/machine.h>
-#include "crm_regs.h"
#define ARM_LP_CLK 166250000
#define GP_LPM_VOLTAGE 775000
diff --git a/arch/arm/mach-mx5/mm.c b/arch/arm/mach-mx5/mm.c
index 8ac23c100bd9..21d654298b54 100644
--- a/arch/arm/mach-mx5/mm.c
+++ b/arch/arm/mach-mx5/mm.c
@@ -16,6 +16,7 @@
#include <mach/hardware.h>
#include <asm/pgtable.h>
#include <asm/mach/map.h>
+#include <mach/iomux-v3.h>
/*!
* @file mach-mx51/mm.c
@@ -60,8 +61,9 @@ void __init mx5_map_io(void)
{
int i;
+ mxc_iomux_v3_init(IO_ADDRESS(IOMUXC_BASE_ADDR));
/* Fixup the mappings for MX53 */
- if (cpu_is_mx53()) {
+ if (cpu_is_mx53() || cpu_is_mx50()) {
for (i = 0; i < ARRAY_SIZE(mx5_io_desc); i++)
mx5_io_desc[i].pfn -= __phys_to_pfn(0x20000000);
}
diff --git a/arch/arm/mach-mx5/mx51_3stack.c b/arch/arm/mach-mx5/mx51_3stack.c
index 7c3d80938777..cc5a205d594d 100644
--- a/arch/arm/mach-mx5/mx51_3stack.c
+++ b/arch/arm/mach-mx5/mx51_3stack.c
@@ -47,7 +47,6 @@
#include <mach/mxc_dvfs.h>
#include "devices.h"
-#include "board-mx51_3stack.h"
#include "iomux.h"
#include "mx51_pins.h"
#include "crm_regs.h"
@@ -60,6 +59,44 @@
*
* @ingroup MSL_MX51
*/
+#define DEBUG_BOARD_BASE_ADDRESS(n) (n)
+/* LAN9217 ethernet base address */
+#define LAN9217_BASE_ADDR(n) (DEBUG_BOARD_BASE_ADDRESS(n))
+
+#define BOARD_IO_ADDR(n) (DEBUG_BOARD_BASE_ADDRESS(n) + 0x20000)
+/* LED switchs */
+#define LED_SWITCH_REG 0x00
+/* buttons */
+#define SWITCH_BUTTONS_REG 0x08
+/* status, interrupt */
+#define INTR_STATUS_REG 0x10
+#define INTR_MASK_REG 0x38
+#define INTR_RESET_REG 0x20
+/* magic word for debug CPLD */
+#define MAGIC_NUMBER1_REG 0x40
+#define MAGIC_NUMBER2_REG 0x48
+/* CPLD code version */
+#define CPLD_CODE_VER_REG 0x50
+/* magic word for debug CPLD */
+#define MAGIC_NUMBER3_REG 0x58
+/* module reset register*/
+#define MODULE_RESET_REG 0x60
+/* CPU ID and Personality ID */
+#define MCU_BOARD_ID_REG 0x68
+
+/* interrupts like external uart , external ethernet etc*/
+#define EXPIO_PARENT_INT IOMUX_TO_IRQ(MX51_PIN_GPIO1_6)
+
+#define EXPIO_INT_ENET (MXC_BOARD_IRQ_START + 0)
+#define EXPIO_INT_XUART_A (MXC_BOARD_IRQ_START + 1)
+#define EXPIO_INT_XUART_B (MXC_BOARD_IRQ_START + 2)
+#define EXPIO_INT_BUTTON_A (MXC_BOARD_IRQ_START + 3)
+#define EXPIO_INT_BUTTON_B (MXC_BOARD_IRQ_START + 4)
+
+/*! This is System IRQ used by LAN9217 */
+#define LAN9217_IRQ EXPIO_INT_ENET
+
+extern int __init mx51_3stack_init_mc13892(void);
extern void __init mx51_3stack_io_init(void);
extern struct cpu_wp *(*get_cpu_wp)(int *wp);
extern void (*set_num_cpu_wp)(int num);
@@ -147,15 +184,77 @@ static struct mxc_vpu_platform_data mxc_vpu_data = {
.reset = mx5_vpu_reset,
};
-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);
+/* workaround for ecspi chipselect pin may not keep correct level when idle */
+static void mx51_3ds_gpio_spi_chipselect_active(int cspi_mode, int status,
+ int chipselect)
+{
+ u32 gpio;
+
+ switch (cspi_mode) {
+ case 1:
+ switch (chipselect) {
+ case 0x1:
+ mxc_request_iomux(MX51_PIN_CSPI1_SS0,
+ IOMUX_CONFIG_ALT0);
+ 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);
+ mxc_request_iomux(MX51_PIN_CSPI1_SS0,
+ IOMUX_CONFIG_GPIO);
+ gpio_request(gpio, "cspi1_ss0");
+ gpio_direction_output(gpio, 0);
+ gpio_set_value(gpio, 1 & (~status));
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2:
+ break;
+ case 3:
+ break;
+ default:
+ break;
+ }
+}
+
+static void mx51_3ds_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;
+ }
+}
+
static struct mxc_spi_master mxcspi1_data = {
.maxchipselect = 4,
.spi_version = 23,
- .chipselect_active = mx51_babbage_gpio_spi_chipselect_active,
- .chipselect_inactive = mx51_babbage_gpio_spi_chipselect_inactive,
+ .chipselect_active = mx51_3ds_gpio_spi_chipselect_active,
+ .chipselect_inactive = mx51_3ds_gpio_spi_chipselect_inactive,
};
static struct mxc_i2c_platform_data mxci2c_data = {
@@ -179,15 +278,11 @@ static struct mxc_dvfs_platform_data dvfs_core_data = {
.reg_id = "SW1",
.clk1_id = "cpu_clk",
.clk2_id = "gpc_dvfs_clk",
- .gpc_cntr_reg_addr = MXC_GPC_CNTR,
- .gpc_vcr_reg_addr = MXC_GPC_VCR,
- .ccm_cdcr_reg_addr = MXC_CCM_CDCR,
- .ccm_cacrr_reg_addr = MXC_CCM_CACRR,
- .ccm_cdhipr_reg_addr = MXC_CCM_CDHIPR,
- .dvfs_thrs_reg_addr = MXC_DVFSTHRS,
- .dvfs_coun_reg_addr = MXC_DVFSCOUN,
- .dvfs_emac_reg_addr = MXC_DVFSEMAC,
- .dvfs_cntr_reg_addr = MXC_DVFSCNTR,
+ .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET,
+ .gpc_vcr_offset = MXC_GPC_VCR_OFFSET,
+ .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET,
+ .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET,
+ .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET,
.prediv_mask = 0x1F800,
.prediv_offset = 11,
.prediv_val = 3,
@@ -685,30 +780,6 @@ static struct fsl_ata_platform_data ata_data = {
.io_reg = NULL,
};
-static int __init mxc_init_srpgconfig(void)
-{
- struct clk *gpcclk = clk_get(NULL, "gpc_dvfs_clk");
- clk_enable(gpcclk);
-
- /* Setup the number of clock cycles to wait for SRPG
- * power up and power down requests.
- */
- __raw_writel(0x010F0201, MXC_SRPG_ARM_PUPSCR);
- __raw_writel(0x010F0201, MXC_SRPG_NEON_PUPSCR);
- __raw_writel(0x00000008, MXC_SRPG_EMPGC0_PUPSCR);
- __raw_writel(0x00000008, MXC_SRPG_EMPGC1_PUPSCR);
-
- __raw_writel(0x01010101, MXC_SRPG_ARM_PDNSCR);
- __raw_writel(0x01010101, MXC_SRPG_NEON_PDNSCR);
- __raw_writel(0x00000018, MXC_SRPG_EMPGC0_PDNSCR);
- __raw_writel(0x00000018, MXC_SRPG_EMPGC1_PDNSCR);
-
- clk_disable(gpcclk);
- clk_put(gpcclk);
-
- return 0;
-}
-
static struct platform_device mxc_wm8903_device = {
.name = "imx-3stack-wm8903",
.id = 0,
@@ -879,6 +950,8 @@ static void __init mxc_board_init(void)
mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk");
mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk");
+ mxc_ipu_data.csi_clk[0] = clk_get(NULL, "csi_mclk1");
+ mxc_ipu_data.csi_clk[1] = clk_get(NULL, "csi_mclk2");
mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk");
clk_put(mxc_spdif_data.spdif_core_clk);
@@ -909,8 +982,8 @@ static void __init mxc_board_init(void)
mxc_register_device(&mxc_pwm1_device, NULL);
mxc_register_device(&mxc_pwm_backlight_device, &mxc_pwm_backlight_data);
mxc_register_device(&mxc_keypad_device, &keypad_plat_data);
- mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0),
- mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0),
+ mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0);
+ mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0);
mxc_register_device(&mxcsdhc1_device, &mmc1_data);
mxc_register_device(&mxcsdhc2_device, &mmc2_data);
mxc_register_device(&mxc_sim_device, &sim_data);
@@ -936,7 +1009,6 @@ static void __init mxc_board_init(void)
#else
mxc_register_device(&mxc_nandv2_mtd_device, &mxc_nand_data);
#endif
- mxc_init_srpgconfig();
mx51_3stack_init_mc13892();
i2c_register_board_info(1, mxc_i2c1_board_info,
@@ -948,6 +1020,8 @@ static void __init mxc_board_init(void)
mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data);
mxc_register_device(&mxc_bt_device, &mxc_bt_data);
mxc_register_device(&mxc_gps_device, &gps_data);
+ mxc_register_device(&mxc_v4l2_device, NULL);
+ mxc_register_device(&mxc_v4l2out_device, NULL);
mx5_usb_dr_init();
mx5_usbh1_init();
diff --git a/arch/arm/mach-mx5/mx51_babbage.c b/arch/arm/mach-mx5/mx51_babbage.c
index 4a962ab6f647..1acc44937e65 100644
--- a/arch/arm/mach-mx5/mx51_babbage.c
+++ b/arch/arm/mach-mx5/mx51_babbage.c
@@ -25,13 +25,13 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
-#include <linux/spi/flash.h>
#include <linux/regulator/consumer.h>
#include <linux/pmic_external.h>
#include <linux/pmic_status.h>
#include <linux/ipu.h>
#include <linux/mxcfb.h>
#include <linux/pwm_backlight.h>
+#include <linux/fec.h>
#include <mach/common.h>
#include <mach/hardware.h>
#include <asm/setup.h>
@@ -39,17 +39,21 @@
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <asm/mach/keypad.h>
+#include <asm/mach/flash.h>
#include <mach/gpio.h>
#include <mach/mmc.h>
#include <mach/mxc_dvfs.h>
#include <mach/mxc_edid.h>
+#include <mach/iomux-mx51.h>
+#include <mach/gpio.h>
#include "devices.h"
-#include "board-mx51_babbage.h"
-#include "iomux.h"
-#include "mx51_pins.h"
#include "crm_regs.h"
#include "usb.h"
+#include <mach/mxc_edid.h>
+#include <linux/android_pmem.h>
+#include <linux/usb/android.h>
+#include <linux/switch.h>
/*!
* @file mach-mx51/mx51_babbage.c
@@ -58,11 +62,181 @@
*
* @ingroup MSL_MX51
*/
-extern void __init mx51_babbage_io_init(void);
+
+#define BABBAGE_SD1_CD (0*32 + 0) /* GPIO_1_0 */
+#define BABBAGE_SD1_WP (0*32 + 1) /* GPIO_1_1 */
+#define BABBAGE_SD2_CD_2_0 (0*32 + 4) /* GPIO_1_4 */
+#define BABBAGE_SD2_WP (0*32 + 5) /* GPIO_1_5 */
+#define BABBAGE_SD2_CD_2_5 (0*32 + 6) /* GPIO_1_6 */
+#define BABBAGE_USBH1_HUB_RST (0*32 + 7) /* GPIO_1_7 */
+#define BABBAGE_PMIC_INT (0*32 + 8) /* GPIO_1_8 */
+
+#define BABBAGE_USB_CLK_EN_B (1*32 + 1) /* GPIO_2_1 */
+#define BABBAGE_OSC_EN_B (1*32 + 2) /* GPIO_2_2 */
+#define BABBAGE_PHY_RESET (1*32 + 5) /* GPIO_2_5 */
+#define BABBAGE_CAM_RESET (1*32 + 7) /* GPIO_2_7 */
+#define BABBAGE_FM_PWR (1*32 + 12) /* GPIO_2_12 */
+#define BABBAGE_VGA_RESET (1*32 + 13) /* GPIO_2_13 */
+#define BABBAGE_FEC_PHY_RESET (1*32 + 14) /* GPIO_2_14 */
+#define BABBAGE_FM_RESET (1*32 + 15) /* GPIO_2_15 */
+#define BABBAGE_AUDAMP_STBY (1*32 + 17) /* GPIO_2_17 */
+#define BABBAGE_POWER_KEY (1*32 + 21) /* GPIO_2_21 */
+
+#define BABBAGE_26M_OSC_EN (2*32 + 1) /* GPIO_3_1 */
+#define BABBAGE_LVDS_POWER_DOWN (2*32 + 3) /* GPIO_3_3 */
+#define BABBAGE_DISP_BRIGHTNESS_CTL (2*32 + 4) /* GPIO_3_4 */
+#define BABBAGE_DVI_RESET (2*32 + 5) /* GPIO_3_5 */
+#define BABBAGE_DVI_POWER (2*32 + 6) /* GPIO_3_6 */
+#define BABBAGE_HEADPHONE_DET (2*32 + 26) /* GPIO_3_26 */
+#define BABBAGE_DVI_DET (2*32 + 28) /* GPIO_3_28 */
+
+#define BABBAGE_LCD_3V3_ON (3*32 + 9) /* GPIO_4_9 */
+#define BABBAGE_LCD_5V_ON (3*32 + 10) /* GPIO_4_10 */
+#define BABBAGE_CAM_LOW_POWER (3*32 + 10) /* GPIO_4_12 */
+#define BABBAGE_DVI_I2C_EN (3*32 + 14) /* GPIO_4_14 */
+#define BABBAGE_CSP1_SS0_GPIO (3*32 + 24) /* GPIO_4_24 */
+#define BABBAGE_AUDIO_CLK_EN (3*32 + 26) /* GPIO_4_26 */
+
+extern int __init mx51_babbage_init_mc13892(void);
extern struct cpu_wp *(*get_cpu_wp)(int *wp);
extern void (*set_num_cpu_wp)(int num);
static int num_cpu_wp = 3;
+static struct pad_desc mx51babbage_pads[] = {
+ /* UART1 */
+ MX51_PAD_UART1_RXD__UART1_RXD,
+ MX51_PAD_UART1_TXD__UART1_TXD,
+ MX51_PAD_UART1_RTS__UART1_RTS,
+ MX51_PAD_UART1_CTS__UART1_CTS,
+
+ /* USB HOST1 */
+ MX51_PAD_USBH1_STP__USBH1_STP,
+ MX51_PAD_USBH1_CLK__USBH1_CLK,
+ MX51_PAD_USBH1_DIR__USBH1_DIR,
+ MX51_PAD_USBH1_NXT__USBH1_NXT,
+ MX51_PAD_USBH1_DATA0__USBH1_DATA0,
+ MX51_PAD_USBH1_DATA1__USBH1_DATA1,
+ MX51_PAD_USBH1_DATA2__USBH1_DATA2,
+ MX51_PAD_USBH1_DATA3__USBH1_DATA3,
+ MX51_PAD_USBH1_DATA4__USBH1_DATA4,
+ MX51_PAD_USBH1_DATA5__USBH1_DATA5,
+ MX51_PAD_USBH1_DATA6__USBH1_DATA6,
+ MX51_PAD_USBH1_DATA7__USBH1_DATA7,
+
+ MX51_PAD_GPIO_1_0__GPIO_1_0,
+ MX51_PAD_GPIO_1_1__GPIO_1_1,
+ MX51_PAD_GPIO_1_4__GPIO_1_4,
+ MX51_PAD_GPIO_1_5__GPIO_1_5,
+ MX51_PAD_GPIO_1_6__GPIO_1_6,
+ MX51_PAD_GPIO_1_7__GPIO_1_7,
+ MX51_PAD_GPIO_1_8__GPIO_1_8,
+ MX51_PAD_UART3_RXD__GPIO_1_22,
+
+ MX51_PAD_EIM_D17__GPIO_2_1,
+ MX51_PAD_EIM_D18__GPIO_2_2,
+ MX51_PAD_EIM_D21__GPIO_2_5,
+ MX51_PAD_EIM_D23__GPIO_2_7,
+ MX51_PAD_EIM_A16__GPIO_2_10,
+ MX51_PAD_EIM_A17__GPIO_2_11,
+ MX51_PAD_EIM_A18__GPIO_2_12,
+ MX51_PAD_EIM_A19__GPIO_2_13,
+ MX51_PAD_EIM_A20__GPIO_2_14,
+ MX51_PAD_EIM_A21__GPIO_2_15,
+ MX51_PAD_EIM_A22__GPIO_2_16,
+ MX51_PAD_EIM_A23__GPIO_2_17,
+ MX51_PAD_EIM_A27__GPIO_2_21,
+ MX51_PAD_EIM_DTACK__GPIO_2_31,
+
+ MX51_PAD_EIM_LBA__GPIO_3_1,
+ MX51_PAD_DI1_D0_CS__GPIO_3_3,
+ MX51_PAD_DISPB2_SER_DIN__GPIO_3_5,
+ MX51_PAD_DISPB2_SER_DIO__GPIO_3_6,
+ MX51_PAD_NANDF_CS0__GPIO_3_16,
+ MX51_PAD_NANDF_CS1__GPIO_3_17,
+ MX51_PAD_NANDF_D14__GPIO_3_26,
+ MX51_PAD_NANDF_D12__GPIO_3_28,
+
+ MX51_PAD_CSI2_D12__GPIO_4_9,
+ MX51_PAD_CSI2_D13__GPIO_4_10,
+ MX51_PAD_CSI2_D19__GPIO_4_12,
+ MX51_PAD_CSI2_HSYNC__GPIO_4_14,
+ MX51_PAD_CSPI1_RDY__GPIO_4_26,
+
+ MX51_PAD_EIM_EB2__FEC_MDIO,
+ MX51_PAD_EIM_EB3__FEC_RDAT1,
+ MX51_PAD_EIM_CS2__FEC_RDAT2,
+ MX51_PAD_EIM_CS3__FEC_RDAT3,
+ MX51_PAD_EIM_CS4__FEC_RX_ER,
+ MX51_PAD_EIM_CS5__FEC_CRS,
+ MX51_PAD_NANDF_RB2__FEC_COL,
+ MX51_PAD_NANDF_RB3__FEC_RXCLK,
+ MX51_PAD_NANDF_RB6__FEC_RDAT0,
+ MX51_PAD_NANDF_RB7__FEC_TDAT0,
+ MX51_PAD_NANDF_CS2__FEC_TX_ER,
+ MX51_PAD_NANDF_CS3__FEC_MDC,
+ MX51_PAD_NANDF_CS4__FEC_TDAT1,
+ MX51_PAD_NANDF_CS5__FEC_TDAT2,
+ MX51_PAD_NANDF_CS6__FEC_TDAT3,
+ MX51_PAD_NANDF_CS7__FEC_TX_EN,
+ MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK,
+
+ MX51_PAD_GPIO_NAND__PATA_INTRQ,
+
+ MX51_PAD_DI_GP4__DI2_PIN15,
+#ifdef CONFIG_FB_MXC_CLAA_WVGA_SYNC_PANEL
+ MX51_PAD_DISP1_DAT22__DISP2_DAT16,
+ MX51_PAD_DISP1_DAT23__DISP2_DAT17,
+
+ MX51_PAD_DI1_D1_CS__GPIO_3_4,
+#endif
+ MX51_PAD_I2C1_CLK__HSI2C_CLK,
+ MX51_PAD_I2C1_DAT__HSI2C_DAT,
+ MX51_PAD_EIM_D16__I2C1_SDA,
+ MX51_PAD_EIM_D19__I2C1_SCL,
+
+ MX51_PAD_GPIO_1_2__PWM_PWMO,
+
+ MX51_PAD_KEY_COL5__I2C2_SDA,
+ MX51_PAD_KEY_COL4__I2C2_SCL,
+
+ MX51_PAD_SD1_CMD__SD1_CMD,
+ MX51_PAD_SD1_CLK__SD1_CLK,
+ MX51_PAD_SD1_DATA0__SD1_DATA0,
+ MX51_PAD_SD1_DATA1__SD1_DATA1,
+ MX51_PAD_SD1_DATA2__SD1_DATA2,
+ MX51_PAD_SD1_DATA3__SD1_DATA3,
+
+ MX51_PAD_SD2_CMD__SD2_CMD,
+ MX51_PAD_SD2_CLK__SD2_CLK,
+ MX51_PAD_SD2_DATA0__SD2_DATA0,
+ MX51_PAD_SD2_DATA1__SD2_DATA1,
+ MX51_PAD_SD2_DATA2__SD2_DATA2,
+ MX51_PAD_SD2_DATA3__SD2_DATA3,
+
+ MX51_PAD_AUD3_BB_TXD__AUD3_BB_TXD,
+ MX51_PAD_AUD3_BB_RXD__AUD3_BB_RXD,
+ MX51_PAD_AUD3_BB_CK__AUD3_BB_CK,
+ MX51_PAD_AUD3_BB_FS__AUD3_BB_FS,
+
+ MX51_PAD_CSPI1_SS1__CSPI1_SS1,
+
+ MX51_PAD_DI_GP3__CSI1_DATA_EN,
+ MX51_PAD_CSI1_D10__CSI1_D10,
+ MX51_PAD_CSI1_D11__CSI1_D11,
+ MX51_PAD_CSI1_D12__CSI1_D12,
+ MX51_PAD_CSI1_D13__CSI1_D13,
+ MX51_PAD_CSI1_D14__CSI1_D14,
+ MX51_PAD_CSI1_D15__CSI1_D15,
+ MX51_PAD_CSI1_D16__CSI1_D16,
+ MX51_PAD_CSI1_D17__CSI1_D17,
+ MX51_PAD_CSI1_D18__CSI1_D18,
+ MX51_PAD_CSI1_D19__CSI1_D19,
+ MX51_PAD_CSI1_VSYNC__CSI1_VSYNC,
+ MX51_PAD_CSI1_HSYNC__CSI1_HSYNC,
+
+ MX51_PAD_OWIRE_LINE__SPDIF_OUT1,
+};
+
/* working point(wp): 0 - 800MHz; 1 - 166.25MHz; */
static struct cpu_wp cpu_wp_auto[] = {
{
@@ -96,6 +270,24 @@ static struct cpu_wp cpu_wp_auto[] = {
static struct fb_videomode video_modes[] = {
{
+ /* NTSC TV output */
+ "TV-NTSC", 60, 720, 480, 74074,
+ 122, 15,
+ 18, 26,
+ 1, 1,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | FB_SYNC_EXT,
+ FB_VMODE_INTERLACED,
+ 0,},
+ {
+ /* PAL TV output */
+ "TV-PAL", 50, 720, 576, 74074,
+ 132, 11,
+ 22, 26,
+ 1, 1,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | FB_SYNC_EXT,
+ FB_VMODE_INTERLACED | FB_VMODE_ODD_FLD_FIRST,
+ 0,},
+ {
/* 720p60 TV output */
"720P60", 60, 1280, 720, 13468,
260, 109,
@@ -106,7 +298,7 @@ static struct fb_videomode video_modes[] = {
FB_VMODE_NONINTERLACED,
0,},
{
- /* MITSUBISHI LVDS panel */
+ /*MITSUBISHI LVDS panel */
"XGA", 60, 1024, 768, 15385,
220, 40,
21, 7,
@@ -114,6 +306,12 @@ static struct fb_videomode video_modes[] = {
0,
FB_VMODE_NONINTERLACED,
0,},
+ {
+ /* 800x480 @ 57 Hz , pixel clk @ 27MHz */
+ "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10,
+ FB_SYNC_CLK_LAT_FALL,
+ FB_VMODE_NONINTERLACED,
+ 0,},
};
struct cpu_wp *mx51_babbage_get_cpu_wp(int *wp)
@@ -166,10 +364,73 @@ static struct mxc_vpu_platform_data mxc_vpu_data = {
.reset = mx5_vpu_reset,
};
-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);
+static struct fec_platform_data fec_data = {
+ .phy = PHY_INTERFACE_MODE_MII,
+ .phy_mask = ~1UL,
+};
+
+/* workaround for ecspi chipselect pin may not keep correct level when idle */
+static void mx51_babbage_gpio_spi_chipselect_active(int cspi_mode, int status,
+ int chipselect)
+{
+ switch (cspi_mode) {
+ case 1:
+ switch (chipselect) {
+ case 0x1:
+ {
+ struct pad_desc cspi1_ss0 = MX51_PAD_CSPI1_SS0__CSPI1_SS0;
+
+ mxc_iomux_v3_setup_pad(&cspi1_ss0);
+ break;
+ }
+ case 0x2:
+ {
+ struct pad_desc cspi1_ss0_gpio = MX51_PAD_CSPI1_SS0__GPIO_4_24;
+
+ mxc_iomux_v3_setup_pad(&cspi1_ss0_gpio);
+ gpio_request(BABBAGE_CSP1_SS0_GPIO, "cspi1-gpio");
+ gpio_direction_output(BABBAGE_CSP1_SS0_GPIO, 0);
+ gpio_set_value(BABBAGE_CSP1_SS0_GPIO, 1 & (~status));
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ case 2:
+ break;
+ case 3:
+ break;
+ default:
+ break;
+ }
+}
+
+static void mx51_babbage_gpio_spi_chipselect_inactive(int cspi_mode, int status,
+ int chipselect)
+{
+ switch (cspi_mode) {
+ case 1:
+ switch (chipselect) {
+ case 0x1:
+ break;
+ case 0x2:
+ gpio_free(BABBAGE_CSP1_SS0_GPIO);
+ break;
+
+ default:
+ break;
+ }
+ break;
+ case 2:
+ break;
+ case 3:
+ break;
+ default:
+ break;
+ }
+}
+
static struct mxc_spi_master mxcspi1_data = {
.maxchipselect = 4,
.spi_version = 23,
@@ -197,15 +458,11 @@ static struct mxc_dvfs_platform_data dvfs_core_data = {
.reg_id = "SW1",
.clk1_id = "cpu_clk",
.clk2_id = "gpc_dvfs_clk",
- .gpc_cntr_reg_addr = MXC_GPC_CNTR,
- .gpc_vcr_reg_addr = MXC_GPC_VCR,
- .ccm_cdcr_reg_addr = MXC_CCM_CDCR,
- .ccm_cacrr_reg_addr = MXC_CCM_CACRR,
- .ccm_cdhipr_reg_addr = MXC_CCM_CDHIPR,
- .dvfs_thrs_reg_addr = MXC_DVFSTHRS,
- .dvfs_coun_reg_addr = MXC_DVFSCOUN,
- .dvfs_emac_reg_addr = MXC_DVFSEMAC,
- .dvfs_cntr_reg_addr = MXC_DVFSCNTR,
+ .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET,
+ .gpc_vcr_offset = MXC_GPC_VCR_OFFSET,
+ .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET,
+ .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET,
+ .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET,
.prediv_mask = 0x1F800,
.prediv_offset = 11,
.prediv_val = 3,
@@ -258,30 +515,73 @@ static struct mxc_fb_platform_data fb_data[] = {
{
.interface_pix_fmt = IPU_PIX_FMT_RGB24,
.mode_str = "1024x768M-16@60",
+ .mode = video_modes,
+ .num_modes = ARRAY_SIZE(video_modes),
},
{
.interface_pix_fmt = IPU_PIX_FMT_RGB565,
- .mode_str = "1024x768M-16@60",
+ .mode_str = "CLAA-WVGA",
+ .mode = video_modes,
+ .num_modes = ARRAY_SIZE(video_modes),
},
};
-static int __initdata enable_vga = { 0 };
-static int __initdata enable_wvga = { 0 };
-static int __initdata enable_tv = { 0 };
-static int __initdata enable_mitsubishi_xga = { 0 };
-
-static void wvga_reset(void)
+extern int primary_di;
+static int __init mxc_init_fb(void)
{
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DI1_D1_CS), 1);
-}
+ if (!machine_is_mx51_babbage())
+ return 0;
-static struct mxc_lcd_platform_data lcd_wvga_data = {
- .reset = wvga_reset,
-};
+ /* DI0-LVDS */
+ gpio_set_value(BABBAGE_LVDS_POWER_DOWN, 0);
+ msleep(1);
+ gpio_set_value(BABBAGE_LVDS_POWER_DOWN, 1);
+ gpio_set_value(BABBAGE_LCD_3V3_ON, 1);
+ gpio_set_value(BABBAGE_LCD_5V_ON, 1);
-static struct platform_device lcd_wvga_device = {
- .name = "lcd_claa",
-};
+ /* DVI Detect */
+ gpio_request(BABBAGE_DVI_DET, "dvi-detect");
+ gpio_direction_input(BABBAGE_DVI_DET);
+ /* DVI Reset - Assert for i2c disabled mode */
+ gpio_request(BABBAGE_DVI_RESET, "dvi-reset");
+ gpio_direction_output(BABBAGE_DVI_RESET, 0);
+ /* DVI Power-down */
+ gpio_request(BABBAGE_DVI_POWER, "dvi-power");
+ gpio_direction_output(BABBAGE_DVI_POWER, 1);
+
+ /* WVGA Reset */
+ gpio_set_value(BABBAGE_DISP_BRIGHTNESS_CTL, 1);
+
+ if (primary_di) {
+ printk(KERN_INFO "DI1 is primary\n");
+
+ /* DI1 -> DP-BG channel: */
+ mxc_fb_devices[1].num_resources = ARRAY_SIZE(mxcfb_resources);
+ mxc_fb_devices[1].resource = mxcfb_resources;
+ mxc_register_device(&mxc_fb_devices[1], &fb_data[1]);
+
+ /* DI0 -> DC channel: */
+ mxc_register_device(&mxc_fb_devices[0], &fb_data[0]);
+ } else {
+ printk(KERN_INFO "DI0 is primary\n");
+
+ /* DI0 -> DP-BG channel: */
+ mxc_fb_devices[0].num_resources = ARRAY_SIZE(mxcfb_resources);
+ mxc_fb_devices[0].resource = mxcfb_resources;
+ mxc_register_device(&mxc_fb_devices[0], &fb_data[0]);
+
+ /* DI1 -> DC channel: */
+ mxc_register_device(&mxc_fb_devices[1], &fb_data[1]);
+ }
+
+ /*
+ * DI0/1 DP-FG channel:
+ */
+ mxc_register_device(&mxc_fb_devices[2], NULL);
+
+ return 0;
+}
+device_initcall(mxc_init_fb);
static int handle_edid(int *pixclk)
{
@@ -370,171 +670,17 @@ static int handle_edid(int *pixclk)
return 0;
}
-static int __init mxc_init_fb(void)
-{
- int pixclk = 0;
-
- if (!machine_is_mx51_babbage())
- return 0;
-
- if (cpu_is_mx51_rev(CHIP_REV_1_1) == 1) {
- enable_vga = 1;
- fb_data[0].mode_str = NULL;
- fb_data[1].mode_str = NULL;
- }
-
- /* DI1: Dumb LCD */
- if (enable_wvga) {
- fb_data[1].interface_pix_fmt = IPU_PIX_FMT_RGB565;
- fb_data[1].mode_str = "800x480M-16@55";
- }
-
- /* DI0: lVDS */
- if (enable_mitsubishi_xga) {
- fb_data[0].interface_pix_fmt = IPU_PIX_FMT_LVDS666;
- fb_data[0].mode = &(video_modes[1]);
-
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DI1_D0_CS), 0);
- msleep(1);
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DI1_D0_CS), 1);
-
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSI2_D12), 1);
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSI2_D13), 1);
- }
-
- /* DVI Detect */
- gpio_request(IOMUX_TO_GPIO(MX51_PIN_NANDF_D12), "nandf_d12");
- gpio_direction_input(IOMUX_TO_GPIO(MX51_PIN_NANDF_D12));
- /* DVI Reset - Assert for i2c disabled mode */
- gpio_request(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIN), "dispb2_ser_din");
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIN), 0);
- gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIN), 0);
- /* DVI Power-down */
- gpio_request(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIO), "dispb2_ser_di0");
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIO), 1);
- gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIO), 0);
-
- mxc_register_device(&lcd_wvga_device, &lcd_wvga_data);
-
- if (cpu_is_mx51_rev(CHIP_REV_1_1) == 2)
- handle_edid(&pixclk);
-
- if (enable_vga) {
- printk(KERN_INFO "VGA monitor is primary\n");
- } else if (enable_wvga) {
- printk(KERN_INFO "WVGA LCD panel is primary\n");
- } else if (enable_tv == 2)
- printk(KERN_INFO "HDTV is primary\n");
- else
- printk(KERN_INFO "DVI monitor is primary\n");
-
- if (enable_tv) {
- printk(KERN_INFO "HDTV is specified as %d\n", enable_tv);
- fb_data[1].interface_pix_fmt = IPU_PIX_FMT_YUV444;
- fb_data[1].mode = &(video_modes[0]);
- }
-
- /* Once a customer knows the platform configuration,
- this should be simplified to what is desired.
- */
- if (enable_vga || enable_wvga || enable_tv == 2) {
- /*
- * DI1 -> DP-BG channel:
- *
- * dev di-out-fmt default-videmode
- *
- * 1. VGA RGB 1024x768M-16@60
- * 2. WVGA RGB 800x480M-16@55
- * 3. TVE YUV video_modes[0]
- */
- mxc_fb_devices[1].num_resources = ARRAY_SIZE(mxcfb_resources);
- mxc_fb_devices[1].resource = mxcfb_resources;
- mxc_register_device(&mxc_fb_devices[1], &fb_data[1]);
- if (fb_data[0].mode_str || fb_data[0].mode)
- /*
- * DI0 -> DC channel:
- *
- * dev di-out-fmt default-videmode
- *
- * 1. LVDS RGB video_modes[1]
- * 2. DVI RGB 1024x768M-16@60
- */
- mxc_register_device(&mxc_fb_devices[0], &fb_data[0]);
- } else {
- /*
- * DI0 -> DP-BG channel:
- *
- * dev di-out-fmt default-videmode
- *
- * 1. LVDS RGB video_modes[1]
- * 2. DVI RGB 1024x768M-16@60
- */
- mxc_fb_devices[0].num_resources = ARRAY_SIZE(mxcfb_resources);
- mxc_fb_devices[0].resource = mxcfb_resources;
- mxc_register_device(&mxc_fb_devices[0], &fb_data[0]);
- if (fb_data[1].mode_str || fb_data[1].mode)
- /*
- * DI1 -> DC channel:
- *
- * dev di-out-fmt default-videmode
- *
- * 1. VGA RGB 1024x768M-16@60
- * 2. WVGA RGB 800x480M-16@55
- * 3. TVE YUV video_modes[0]
- */
- mxc_register_device(&mxc_fb_devices[1], &fb_data[1]);
- }
-
- /*
- * DI0/1 DP-FG channel:
- */
- mxc_register_device(&mxc_fb_devices[2], NULL);
-
- return 0;
-}
-device_initcall(mxc_init_fb);
-
-static int __init vga_setup(char *__unused)
-{
- enable_vga = 1;
- return 1;
-}
-__setup("vga", vga_setup);
-
-static int __init wvga_setup(char *__unused)
-{
- enable_wvga = 1;
- return 1;
-}
-__setup("wvga", wvga_setup);
-
-static int __init mitsubishi_xga_setup(char *__unused)
-{
- enable_mitsubishi_xga = 1;
- return 1;
-}
-__setup("mitsubishi_xga", mitsubishi_xga_setup);
-
-static int __init tv_setup(char *s)
-{
- enable_tv = 1;
- if (strcmp(s, "2") == 0 || strcmp(s, "=2") == 0)
- enable_tv = 2;
- return 1;
-}
-__setup("hdtv", tv_setup);
-
static void dvi_reset(void)
{
- gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIN), 0);
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIN), 0);
+ gpio_direction_output(BABBAGE_DVI_RESET, 0);
+ gpio_set_value(BABBAGE_DVI_RESET, 0);
msleep(50);
/* do reset */
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIN), 1);
+ gpio_set_value(BABBAGE_DVI_RESET, 1);
msleep(20); /* tRES >= 50us */
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_DIN), 0);
+ gpio_set_value(BABBAGE_DVI_RESET, 0);
}
static struct mxc_lcd_platform_data dvi_data = {
@@ -545,14 +691,13 @@ static struct mxc_lcd_platform_data dvi_data = {
static void vga_reset(void)
{
- gpio_request(IOMUX_TO_GPIO(MX51_PIN_EIM_A19), "eim_a19");
- gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A19), 0);
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A19), 0);
+
+ gpio_set_value(BABBAGE_VGA_RESET, 0);
msleep(50);
/* do reset */
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A19), 1);
+ gpio_set_value(BABBAGE_VGA_RESET, 1);
msleep(10); /* tRES >= 50us */
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A19), 0);
+ gpio_set_value(BABBAGE_VGA_RESET, 0);
}
static struct mxc_lcd_platform_data vga_data = {
@@ -565,22 +710,23 @@ static struct mxc_lcd_platform_data vga_data = {
static void si4702_reset(void)
{
return;
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A21), 0);
+
+ gpio_set_value(BABBAGE_FM_RESET, 0);
msleep(100);
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A21), 1);
+ gpio_set_value(BABBAGE_FM_RESET, 1);
msleep(100);
}
static void si4702_clock_ctl(int flag)
{
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A18), flag);
+ gpio_set_value(BABBAGE_FM_PWR, flag);
msleep(100);
}
static void si4702_gpio_get(void)
{
- gpio_request(IOMUX_TO_GPIO(MX51_PIN_EIM_A18), "eim_a18");
- gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A18), 0);
+ gpio_request(BABBAGE_FM_PWR, "fm-power");
+ gpio_direction_output(BABBAGE_FM_PWR, 0);
}
static void si4702_gpio_put(void)
@@ -706,9 +852,9 @@ static int sdhc_write_protect(struct device *dev)
unsigned short rc = 0;
if (to_platform_device(dev)->id == 0)
- rc = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_1));
+ rc = gpio_get_value(BABBAGE_SD1_WP);
else
- rc = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5));
+ rc = gpio_get_value(BABBAGE_SD2_WP);
return rc;
}
@@ -718,25 +864,26 @@ static unsigned int sdhc_get_card_det_status(struct device *dev)
int ret;
if (to_platform_device(dev)->id == 0) {
- ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_0));
+ ret = gpio_get_value(BABBAGE_SD1_CD);
return ret;
} else { /* config the det pin for SDHC2 */
if (board_is_rev(BOARD_REV_2))
/* BB2.5 */
- ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_6));
+ ret = gpio_get_value(BABBAGE_SD2_CD_2_5);
else
/* BB2.0 */
- ret = gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_GPIO1_4));
+ ret = gpio_get_value(BABBAGE_SD2_CD_2_0);
return ret;
}
}
static struct mxc_mmc_platform_data mmc1_data = {
- .ocr_mask = MMC_VDD_31_32,
+ .ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 |
+ MMC_VDD_31_32,
.caps = MMC_CAP_4_BIT_DATA,
- .min_clk = 400000,
+ .min_clk = 150000,
.max_clk = 52000000,
- .card_inserted_state = 1,
+ .card_inserted_state = 0,
.status = sdhc_get_card_det_status,
.wp_status = sdhc_write_protect,
.clock_mmc = "esdhc_clk",
@@ -753,27 +900,25 @@ static struct mxc_mmc_platform_data mmc2_data = {
.status = sdhc_get_card_det_status,
.wp_status = sdhc_write_protect,
.clock_mmc = "esdhc_clk",
+ .clk_always_on = 1,
};
static int mxc_sgtl5000_amp_enable(int enable)
{
- gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_EIM_A23), enable ? 1 : 0);
+ gpio_set_value(BABBAGE_AUDAMP_STBY, enable ? 1 : 0);
return 0;
}
static int headphone_det_status(void)
{
- if (cpu_is_mx51_rev(CHIP_REV_1_1) == 2)
- return (gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_NANDF_D14)) == 0);
-
- return gpio_get_value(IOMUX_TO_GPIO(MX51_PIN_NANDF_CS0));
+ return (gpio_get_value(BABBAGE_HEADPHONE_DET) == 0);
}
static struct mxc_audio_platform_data sgtl5000_data = {
.ssi_num = 1,
.src_port = 2,
.ext_port = 3,
- .hp_irq = IOMUX_TO_IRQ(MX51_PIN_NANDF_D14),
+ .hp_irq = IOMUX_TO_IRQ_V3(BABBAGE_HEADPHONE_DET),
.hp_status = headphone_det_status,
.amp_enable = mxc_sgtl5000_amp_enable,
.sysclk = 12288000,
@@ -783,6 +928,41 @@ static struct platform_device mxc_sgtl5000_device = {
.name = "imx-3stack-sgtl5000",
};
+static int __initdata enable_w1 = { 0 };
+static int __init w1_setup(char *__unused)
+{
+ enable_w1 = 1;
+ return cpu_is_mx51();
+}
+
+__setup("w1", w1_setup);
+
+static struct android_pmem_platform_data android_pmem_pdata = {
+ .name = "pmem_adsp",
+ .start = 0,
+ .size = SZ_32M,
+ .no_allocator = 0,
+ .cached = PMEM_NONCACHE_NORMAL,
+};
+
+static struct android_pmem_platform_data android_pmem_gpu_pdata = {
+ .name = "pmem_gpu",
+ .start = 0,
+ .size = SZ_32M,
+ .no_allocator = 0,
+ .cached = PMEM_CACHE_ENABLE,
+};
+
+static struct android_usb_platform_data android_usb_pdata = {
+ .vendor_id = 0x0bb4,
+ .product_id = 0x0c01,
+ .adb_product_id = 0x0c02,
+ .version = 0x0100,
+ .product_name = "Android Phone",
+ .manufacturer_name = "Freescale",
+ .nluns = 3,
+};
+
/*!
* Board specific fixup function. It is called by \b setup_arch() in
* setup.c file very early on during kernel starts. It allows the user to
@@ -804,12 +984,32 @@ static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags,
int left_mem = 0;
int gpu_mem = SZ_64M;
int fb_mem = SZ_32M;
+ int size;
mxc_set_cpu_type(MXC_CPU_MX51);
get_cpu_wp = mx51_babbage_get_cpu_wp;
set_num_cpu_wp = mx51_babbage_set_num_cpu_wp;
+ for_each_tag(t, tags) {
+ if (t->hdr.tag != ATAG_MEM)
+ continue;
+ size = t->u.mem.size;
+
+ android_pmem_pdata.start =
+ PHYS_OFFSET + size - android_pmem_pdata.size;
+ android_pmem_gpu_pdata.start =
+ android_pmem_pdata.start - android_pmem_gpu_pdata.size;
+ gpu_device.resource[5].start =
+ android_pmem_gpu_pdata.start - SZ_16M;
+ gpu_device.resource[5].end =
+ gpu_device.resource[5].start + SZ_16M - 1;
+ size -= android_pmem_pdata.size;
+ size -= android_pmem_gpu_pdata.size;
+ size -= SZ_16M;
+ t->u.mem.size = size;
+ }
+#if 0
for_each_tag(mem_tag, tags) {
if (mem_tag->hdr.tag == ATAG_MEM) {
total_mem = mem_tag->u.mem.size;
@@ -866,7 +1066,82 @@ static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags,
}
#endif
}
+#endif
+}
+
+static struct switch_dev dvi_sdev;
+static int state;
+static struct delayed_work dvi_det_work;
+static void dvi_update_detect_status(void)
+{
+ int level;
+
+ level = gpio_get_value(BABBAGE_DVI_DET);
+ if (level == 1) {
+ pr_info(KERN_INFO "DVI device plug-in\n");
+ state = 1;
+ } else {
+ pr_info(KERN_INFO "DVI device plug-out\n");
+ state = 0;
+ }
+ switch_set_state(&dvi_sdev, state);
+}
+
+static void dvi_work_func(struct work_struct *work)
+{
+ dvi_update_detect_status();
+}
+
+static irqreturn_t dvi_det_int(int irq, void *dev_id)
+{
+ schedule_delayed_work(&dvi_det_work, msecs_to_jiffies(10));
+ return 0;
+}
+
+static ssize_t print_switch_name(struct switch_dev *sdev, char *buf)
+{
+ return sprintf(buf, "dvi_det\n");
+}
+
+static ssize_t print_switch_state(struct switch_dev *sdev, char *buf)
+{
+ return sprintf(buf, "%s\n", (state ? "online" : "offline"));
+}
+
+static int __init mxc_init_dvi_det(void)
+{
+ int irq, level, ret;
+
+ if (!machine_is_mx51_babbage())
+ return 0;
+
+ dvi_sdev.name = "dvi_det";
+ dvi_sdev.print_name = print_switch_name;
+ dvi_sdev.print_state = print_switch_state;
+ switch_dev_register(&dvi_sdev);
+
+ level = gpio_get_value(BABBAGE_DVI_DET);
+ if (level == 1) {
+ pr_info(KERN_INFO "DVI device plug-in\n");
+ state = 1;
+ } else {
+ pr_info(KERN_INFO "DVI device plug-out\n");
+ state = 0;
+ }
+
+ INIT_DELAYED_WORK(&dvi_det_work, dvi_work_func);
+
+ irq = IOMUX_TO_IRQ_V3(BABBAGE_DVI_DET);
+ set_irq_type(irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING);
+ ret = request_irq(irq, dvi_det_int, 0, "dvi_det", 0);
+ if (ret) {
+ pr_info("register DVI detect interrupt failed\n");
+ return -1;
+ }
+ return 0;
}
+late_initcall(mxc_init_dvi_det);
+
#define PWGT1SPIEN (1<<15)
#define PWGT2SPIEN (1<<16)
@@ -899,7 +1174,7 @@ static int __init mxc_init_power_key(void)
{
/* Set power key as wakeup resource */
int irq, ret;
- irq = IOMUX_TO_IRQ(MX51_PIN_EIM_A27);
+ irq = IOMUX_TO_IRQ_V3(BABBAGE_POWER_KEY);
set_irq_type(irq, IRQF_TRIGGER_RISING);
ret = request_irq(irq, power_key_int, 0, "power_key", 0);
if (ret)
@@ -910,6 +1185,113 @@ static int __init mxc_init_power_key(void)
}
late_initcall(mxc_init_power_key);
+static void __init mx51_babbage_io_init(void)
+{
+ mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads,
+ ARRAY_SIZE(mx51babbage_pads));
+
+ gpio_request(BABBAGE_PMIC_INT, "pmic-int");
+ gpio_request(BABBAGE_SD1_CD, "sdhc1-detect");
+ gpio_request(BABBAGE_SD1_WP, "sdhc1-wp");
+
+ gpio_direction_input(BABBAGE_PMIC_INT);
+ gpio_direction_input(BABBAGE_SD1_CD);
+ gpio_direction_input(BABBAGE_SD1_WP);
+
+ if (board_is_rev(BOARD_REV_2)) {
+ /* SD2 CD for BB2.5 */
+ gpio_request(BABBAGE_SD2_CD_2_5, "sdhc2-detect");
+ gpio_direction_input(BABBAGE_SD2_CD_2_5);
+ } else {
+ /* SD2 CD for BB2.0 */
+ gpio_request(BABBAGE_SD2_CD_2_0, "sdhc2-detect");
+ gpio_direction_input(BABBAGE_SD2_CD_2_0);
+ }
+ gpio_request(BABBAGE_SD2_WP, "sdhc2-wp");
+ gpio_direction_input(BABBAGE_SD2_WP);
+
+ /* reset usbh1 hub */
+ gpio_request(BABBAGE_USBH1_HUB_RST, "hub-rst");
+ gpio_direction_output(BABBAGE_USBH1_HUB_RST, 0);
+ gpio_set_value(BABBAGE_USBH1_HUB_RST, 0);
+ msleep(1);
+ gpio_set_value(BABBAGE_USBH1_HUB_RST, 1);
+
+ /* reset FEC PHY */
+ gpio_request(BABBAGE_FEC_PHY_RESET, "fec-phy-reset");
+ gpio_direction_output(BABBAGE_FEC_PHY_RESET, 0);
+ msleep(10);
+ gpio_set_value(BABBAGE_FEC_PHY_RESET, 1);
+
+ /* reset FM */
+ gpio_request(BABBAGE_FM_RESET, "fm-reset");
+ gpio_direction_output(BABBAGE_FM_RESET, 0);
+ msleep(10);
+ gpio_set_value(BABBAGE_FM_RESET, 1);
+
+ /* Drive 26M_OSC_EN line high */
+ gpio_request(BABBAGE_26M_OSC_EN, "26m-osc-en");
+ gpio_direction_output(BABBAGE_26M_OSC_EN, 1);
+
+ /* Drive USB_CLK_EN_B line low */
+ gpio_request(BABBAGE_USB_CLK_EN_B, "usb-clk_en_b");
+ gpio_direction_output(BABBAGE_USB_CLK_EN_B, 0);
+
+ /* De-assert USB PHY RESETB */
+ gpio_request(BABBAGE_PHY_RESET, "usb-phy-reset");
+ gpio_direction_output(BABBAGE_PHY_RESET, 1);
+
+ /* hphone_det_b */
+ gpio_request(BABBAGE_HEADPHONE_DET, "hphone-det");
+ gpio_direction_input(BABBAGE_HEADPHONE_DET);
+
+ /* audio_clk_en_b */
+ gpio_request(BABBAGE_AUDIO_CLK_EN, "audio-clk-en");
+ gpio_direction_output(BABBAGE_AUDIO_CLK_EN, 0);
+
+ /* power key */
+ gpio_request(BABBAGE_POWER_KEY, "power-key");
+ gpio_direction_input(BABBAGE_POWER_KEY);
+
+ if (cpu_is_mx51_rev(CHIP_REV_3_0) > 0) {
+ /* DVI_I2C_ENB = 0 tristates the DVI I2C level shifter */
+ gpio_request(BABBAGE_DVI_I2C_EN, "dvi-i2c-en");
+ gpio_direction_output(BABBAGE_DVI_I2C_EN, 0);
+ }
+
+ /* Deassert VGA reset to free i2c bus */
+ gpio_request(BABBAGE_VGA_RESET, "vga-reset");
+ gpio_direction_output(BABBAGE_VGA_RESET, 1);
+
+ /* LCD related gpio */
+ gpio_request(BABBAGE_DISP_BRIGHTNESS_CTL, "disp-brightness-ctl");
+ gpio_request(BABBAGE_LVDS_POWER_DOWN, "lvds-power-down");
+ gpio_request(BABBAGE_LCD_3V3_ON, "lcd-3v3-on");
+ gpio_request(BABBAGE_LCD_5V_ON, "lcd-5v-on");
+ gpio_direction_output(BABBAGE_DISP_BRIGHTNESS_CTL, 0);
+ gpio_direction_output(BABBAGE_LVDS_POWER_DOWN, 0);
+ gpio_direction_output(BABBAGE_LCD_3V3_ON, 0);
+ gpio_direction_output(BABBAGE_LCD_5V_ON, 0);
+
+ /* Camera reset */
+ gpio_request(BABBAGE_CAM_RESET, "cam-reset");
+ gpio_direction_output(BABBAGE_CAM_RESET, 1);
+
+ /* Camera low power */
+ gpio_request(BABBAGE_CAM_LOW_POWER, "cam-low-power");
+ gpio_direction_output(BABBAGE_CAM_LOW_POWER, 0);
+
+ /* OSC_EN */
+ gpio_request(BABBAGE_OSC_EN_B, "osc-en");
+ gpio_direction_output(BABBAGE_OSC_EN_B, 1);
+
+ if (enable_w1) {
+ /* OneWire */
+ struct pad_desc onewire = MX51_PAD_OWIRE_LINE__OWIRE_LINE;
+ mxc_iomux_v3_setup_pad(&onewire);
+ }
+}
+
/*!
* Board specific initialization.
*/
@@ -917,14 +1299,16 @@ static void __init mxc_board_init(void)
{
mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk");
mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk");
+ mxc_ipu_data.csi_clk[0] = clk_get(NULL, "csi_mclk1");
+ mxc_ipu_data.csi_clk[1] = clk_get(NULL, "csi_mclk2");
mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk");
clk_put(mxc_spdif_data.spdif_core_clk);
/* SD card detect irqs */
- mxcsdhc2_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO1_6);
- mxcsdhc2_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO1_6);
- mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0);
- mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0);
+ mxcsdhc2_device.resource[2].start = IOMUX_TO_IRQ_V3(BABBAGE_SD2_CD_2_5);
+ mxcsdhc2_device.resource[2].end = IOMUX_TO_IRQ_V3(BABBAGE_SD2_CD_2_5);
+ mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ_V3(BABBAGE_SD1_CD);
+ mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ_V3(BABBAGE_SD1_CD);
mxc_cpu_common_init();
mxc_register_gpios();
@@ -952,14 +1336,17 @@ static void __init mxc_board_init(void)
mxc_register_device(&mxc_pwm1_device, NULL);
mxc_register_device(&mxc_pwm_backlight_device, &mxc_pwm_backlight_data);
mxc_register_device(&mxc_keypad_device, &keypad_plat_data);
- mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0),
- mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0),
mxc_register_device(&mxcsdhc1_device, &mmc1_data);
mxc_register_device(&mxcsdhc2_device, &mmc2_data);
mxc_register_device(&mxc_ssi1_device, NULL);
mxc_register_device(&mxc_ssi2_device, NULL);
mxc_register_device(&mxc_alsa_spdif_device, &mxc_spdif_data);
- mxc_register_device(&mxc_fec_device, NULL);
+ mxc_register_device(&mxc_fec_device, &fec_data);
+ mxc_register_device(&mxc_v4l2_device, NULL);
+ mxc_register_device(&mxc_v4l2out_device, NULL);
+ mxc_register_device(&mxc_android_pmem_device, &android_pmem_pdata);
+ mxc_register_device(&mxc_android_pmem_gpu_device, &android_pmem_gpu_pdata);
+ mxc_register_device(&android_usb_device, &android_usb_pdata);
mx51_babbage_init_mc13892();
@@ -990,8 +1377,8 @@ static void __init mxc_board_init(void)
if (cpu_is_mx51_rev(CHIP_REV_1_1) == 2) {
sgtl5000_data.sysclk = 26000000;
}
- gpio_request(IOMUX_TO_GPIO(MX51_PIN_EIM_A23), "eim_a23");
- gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_EIM_A23), 0);
+ gpio_request(BABBAGE_AUDAMP_STBY, "audioamp-stdby");
+ gpio_direction_output(BABBAGE_AUDAMP_STBY, 0);
mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data);
mx5_usb_dr_init();
diff --git a/arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c b/arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c
index 4aa15f3c2515..1626c95d54d2 100644
--- a/arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c
+++ b/arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c
@@ -23,8 +23,8 @@
#include <linux/regulator/machine.h>
#include <linux/mfd/mc13892/core.h>
#include <mach/irqs.h>
-#include "iomux.h"
-#include "mx51_pins.h"
+#include <mach/hardware.h>
+#include <mach/iomux-mx51.h>
/*
* Convenience conversion.
@@ -406,8 +406,8 @@ static struct mc13892_platform_data mc13892_plat = {
static struct spi_board_info __initdata mc13892_spi_device = {
.modalias = "pmic_spi",
- .irq = IOMUX_TO_IRQ(MX51_PIN_GPIO1_8),
- .max_speed_hz = 1000000, /* max spi SCK clock speed in HZ */
+ .irq = IOMUX_TO_IRQ_V3(8),
+ .max_speed_hz = 6000000, /* max spi SCK clock speed in HZ */
.bus_num = 1,
.chip_select = 0,
.platform_data = &mc13892_plat,
diff --git a/arch/arm/mach-mx5/mx51_ccwmx51js.c b/arch/arm/mach-mx5/mx51_ccwmx51js.c
index 63e0377e751b..bbacfc981d73 100644
--- a/arch/arm/mach-mx5/mx51_ccwmx51js.c
+++ b/arch/arm/mach-mx5/mx51_ccwmx51js.c
@@ -41,8 +41,6 @@
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <mach/memory.h>
-#include <linux/input.h>
-#include <linux/gpio_keys.h>
#include <mach/gpio.h>
#include <mach/mmc.h>
#include <mach/mxc_dvfs.h>
@@ -53,13 +51,16 @@
#include "mx51_pins.h"
#include "devices_ccwmx51.h"
#include "usb.h"
+#include "linux/android_pmem.h"
+#include "linux/usb/android.h"
extern struct cpu_wp *(*get_cpu_wp)(int *wp);
extern void (*set_num_cpu_wp)(int num);
static int num_cpu_wp = 3;
+u8 ccwmx51_swap_bi = 0;
/* working point(wp): 0 - 800MHz; 1 - 166.25MHz; */
-static struct cpu_wp cpu_wp_auto[] = {
+static struct cpu_wp cpu_wp_auto_800[] = {
{
.pll_rate = 1000000000,
.cpu_rate = 1000000000,
@@ -86,13 +87,56 @@ static struct cpu_wp cpu_wp_auto[] = {
.mfd = 2,
.mfn = 1,
.cpu_podf = 4,
- .cpu_voltage = 850000,},
+ .cpu_voltage = 900000,},
+};
+
+static struct cpu_wp cpu_wp_auto_600[] = {
+ {
+ .pll_rate = 600000000,
+ .cpu_rate = 600000000,
+ .pdf = 0,
+ .mfi = 6,
+ .mfd = 3,
+ .mfn = 1,
+ .cpu_podf = 0,
+ .cpu_voltage = 1000000,},
+ {
+ .pll_rate = 600000000,
+ .cpu_rate = 150000000,
+ .pdf = 3,
+ .mfi = 6,
+ .mfd = 3,
+ .mfn = 1,
+ .cpu_podf = 3,
+ .cpu_voltage = 950000,},
};
+static u32 ccwmx51_get_cpu_freq(void)
+{
+ u32 cpu_freq = 800000000;
+
+ switch (system_serial_low & 0xff) {
+ case 4:
+ case 5: cpu_freq = 600000000;
+ num_cpu_wp = 2;
+ break;
+ }
+
+ return cpu_freq;
+}
+
struct cpu_wp *mx51_get_cpu_wp(int *wp)
{
+ u32 cpu_clk_rate = ccwmx51_get_cpu_freq();
+
*wp = num_cpu_wp;
- return cpu_wp_auto;
+
+ if (cpu_clk_rate == 800000000) {
+ return cpu_wp_auto_800;
+ } else if (cpu_clk_rate == 600000000) {
+ return cpu_wp_auto_600;
+ }
+ return NULL;
}
void mx51_set_num_cpu_wp(int num)
@@ -101,6 +145,36 @@ void mx51_set_num_cpu_wp(int num)
return;
}
+#if defined CONFIG_ANDROID_PMEM
+static struct android_pmem_platform_data android_pmem_pdata = {
+ .name = "pmem_adsp",
+ .start = 0,
+ .size = SZ_32M,
+ .no_allocator = 0,
+ .cached = PMEM_NONCACHE_NORMAL,
+};
+
+static struct android_pmem_platform_data android_pmem_gpu_pdata = {
+ .name = "pmem_gpu",
+ .start = 0,
+ .size = SZ_32M,
+ .no_allocator = 0,
+ .cached = PMEM_CACHE_ENABLE,
+};
+#endif
+
+#ifdef CONFIG_USB_ANDROID
+static struct android_usb_platform_data android_usb_pdata = {
+ .vendor_id = 0x0bb4,
+ .product_id = 0x0c01,
+ .adb_product_id = 0x0c02,
+ .version = 0x0100,
+ .product_name = "Android Phone",
+ .manufacturer_name = "Freescale",
+ .nluns = 3,
+};
+#endif
+
/*!
* Board specific fixup function. It is called by \b setup_arch() in
* setup.c file very early on during kernel starts. It allows the user to
@@ -115,19 +189,48 @@ void mx51_set_num_cpu_wp(int num)
static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags,
char **cmdline, struct meminfo *mi)
{
- char *str;
struct tag *t;
+#ifdef CONFIG_ANDROID
+ int size;
+#else
+ char *str;
struct tag *mem_tag = 0;
int total_mem = SZ_512M;
int left_mem = 0;
int gpu_mem = SZ_64M;
- int fb_mem = SZ_32M;
+ int fb_mem = FB_MEM_SIZE;
+#endif
mxc_set_cpu_type(MXC_CPU_MX51);
get_cpu_wp = mx51_get_cpu_wp;
set_num_cpu_wp = mx51_set_num_cpu_wp;
+#ifdef CONFIG_ANDROID
+ // TODO: Dual head support for Android.
+ // See commit 358e938e78b3380357f8f0c6dd54fa9fe4cc84c5
+ // This commit removes Digi's dual display customizations
+
+ for_each_tag(t, tags) {
+ if (t->hdr.tag != ATAG_MEM)
+ continue;
+ size = t->u.mem.size;
+
+ android_pmem_pdata.start =
+ PHYS_OFFSET + size - android_pmem_pdata.size;
+ android_pmem_gpu_pdata.start =
+ android_pmem_pdata.start - android_pmem_gpu_pdata.size;
+ gpu_device.resource[5].start =
+ android_pmem_gpu_pdata.start - SZ_16M;
+ gpu_device.resource[5].end =
+ gpu_device.resource[5].start + SZ_16M - 1;
+ size -= android_pmem_pdata.size;
+ size -= android_pmem_gpu_pdata.size;
+ size -= SZ_16M;
+ t->u.mem.size = size;
+ }
+
+#else
for_each_tag(mem_tag, tags) {
if (mem_tag->hdr.tag == ATAG_MEM) {
total_mem = mem_tag->u.mem.size;
@@ -166,6 +269,9 @@ static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags,
}
mem_tag->u.mem.size = left_mem;
+#if defined(CONFIG_CCWMX51_DISP1) && defined(CONFIG_CCWMX51_DISP2)
+ fb_mem = fb_mem / 2; /* Divide the mem for between the displays */
+#endif
/*reserve memory for gpu*/
gpu_device.resource[5].start =
mem_tag->u.mem.start + left_mem;
@@ -178,12 +284,23 @@ static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags,
gpu_device.resource[5].end + 1;
mxcfb_resources[0].end =
mxcfb_resources[0].start + fb_mem - 1;
+#if defined(CONFIG_CCWMX51_DISP1) && defined(CONFIG_CCWMX51_DISP2)
+ mxcfb_resources[1].start =
+ mxcfb_resources[0].end + 1;
+ mxcfb_resources[1].end =
+ mxcfb_resources[1].start + fb_mem - 1;
+#endif
} else {
mxcfb_resources[0].start = 0;
mxcfb_resources[0].end = 0;
+ mxcfb_resources[1].start = 0;
+ mxcfb_resources[1].end = 0;
}
#endif
}
+#endif
+
+
}
#define PWGT1SPIEN (1<<15)
@@ -203,97 +320,20 @@ static void mxc_power_off(void)
#endif
}
-/*
- * GPIO Buttons
- */
-#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-static struct gpio_keys_button ccwmx51js_buttons[] = {
- {
- .gpio = IOMUX_TO_GPIO(MX51_PIN_GPIO1_8),
- .code = BTN_1,
- .desc = "Button 1",
- .active_low = 1,
- .wakeup = 1,
- },
- {
- .gpio = IOMUX_TO_GPIO(MX51_PIN_GPIO1_1),
- .code = BTN_2,
- .desc = "Button 2",
- .active_low = 1,
- .wakeup = 1,
- }
-};
-
-static struct gpio_keys_platform_data ccwmx51js_button_data = {
- .buttons = ccwmx51js_buttons,
- .nbuttons = ARRAY_SIZE(ccwmx51js_buttons),
-};
-
-static struct platform_device ccwmx51js_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &ccwmx51js_button_data,
- }
-};
-
-static void __init ccwmx51js_add_device_buttons(void)
-{
- platform_device_register(&ccwmx51js_button_device);
-}
-#else
-static void __init ek_add_device_buttons(void) {}
-#endif
-
-
-#if defined(CONFIG_NEW_LEDS)
-
-/*
- * GPIO LEDs
- */
-static struct gpio_led_platform_data led_data;
-
-static struct gpio_led ccwmx51js_leds[] = {
- {
- .name = "LED1",
- .gpio = IOMUX_TO_GPIO(MX51_PIN_NANDF_RB2),
- .active_low = 1,
- .default_trigger = "none",
- },
- {
- .name = "LED2",
- .gpio = IOMUX_TO_GPIO(MX51_PIN_NANDF_RB1),
- .active_low = 1,
- .default_trigger = "none",
- }
-};
-
-static struct platform_device ccwmx51js_gpio_leds_device = {
- .name = "leds-gpio",
- .id = -1,
- .dev.platform_data = &led_data,
-};
-
-void __init ccwmx51js_gpio_leds(struct gpio_led *leds, int nr)
-{
- if (!nr)
- return;
-
- led_data.leds = leds;
- led_data.num_leds = nr;
- platform_device_register(&ccwmx51js_gpio_leds_device);
-}
-
-#else
-void __init at91_gpio_leds(struct gpio_led *leds, int nr) {}
-#endif
-
/*!
* Board specific initialization.
*/
static void __init mxc_board_init(void)
{
+ /* Setup hwid information, passed through Serial ATAG */
+ ccwmx51_set_mod_variant(system_serial_low & 0xff);
+ ccwmx51_set_mod_revision((system_serial_low >> 8) & 0xff);
+ ccwmx51_set_mod_sn(((system_serial_low << 8) & 0xff000000) |
+ ((system_serial_low >> 8) & 0x00ff0000) |
+ ((system_serial_high << 8) & 0x0000ff00) |
+ ((system_serial_high >> 8) & 0xff));
+
+ ccwmx51_swap_bi = system_serial_high >> 16;
mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk");
mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk");
@@ -304,6 +344,7 @@ static void __init mxc_board_init(void)
mxc_cpu_common_init();
mxc_register_gpios();
ccwmx51_io_init();
+ ccwmx51_init_devices();
mxc_register_device(&mxc_wdt_device, NULL);
mxc_register_device(&mxcspi1_device, &mxcspi1_data);
@@ -330,23 +371,29 @@ static void __init mxc_board_init(void)
mxc_register_device(&mxc_dvfs_per_device, &dvfs_per_data);
mxc_register_device(&mxc_iim_device, NULL);
mxc_register_device(&gpu_device, NULL);
-#if defined(CONFIG_UIO_PDRV_GENIRQ) || defined(CONFIG_UIO_PDRV_GENIRQ_MODULE)
- mxc_register_device(&mxc_gpu2d_device, &gpu2d_platform_data);
+#if defined (CONFIG_MXC_SECURITY_SCC2)
+ mxc_register_device(&mxcscc_device, NULL);
#endif
mxc_register_device(&mxc_pwm1_device, NULL);
mxc_register_device(&mxc_pwm_backlight_device, &mxc_pwm_backlight_data);
-
-#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE)
- /* SD card detect irqs */
- mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0);
- mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO1_0);
- mxcsdhc3_device.resource[2].start = IOMUX_TO_IRQ(MX51_PIN_GPIO_NAND);
- mxcsdhc3_device.resource[2].end = IOMUX_TO_IRQ(MX51_PIN_GPIO_NAND);
- mxc_register_device(&mxcsdhc1_device, &mmc1_data);
- mxc_register_device(&mxcsdhc3_device, &mmc3_data);
+#ifdef CONFIG_ANDROID_PMEM
+ mxc_register_device(&mxc_android_pmem_device, &android_pmem_pdata);
+ mxc_register_device(&mxc_android_pmem_gpu_device, &android_pmem_gpu_pdata);
#endif
+#ifdef CONFIG_USB_ANDROID
+ mxc_register_device(&android_usb_device, &android_usb_pdata);
+#endif
+
+#ifdef CONFIG_ESDHCI_MXC_SELECT1
+ ccwmx51_register_sdio(0); /* SDHC1 */
+#endif /* CONFIG_ESDHCI_MXC_SELECT1 */
+#if defined(CONFIG_ESDHCI_MXC_SELECT3) && \
+ (!defined(CONFIG_PATA_FSL) && !defined(CONFIG_PATA_FSL_MODULE))
+ ccwmx51_register_sdio(2); /* SDHC3 */
+#endif /* CONFIG_ESDHCI_MXC_SELECT3 && !CONFIG_PATA_FSL && !CONFIG_PATA_FSL_MODULE */
+
#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)
- mxc_register_device(&mxc_fec_device, NULL);
+ mxc_register_device(&mxc_fec_device, &fec_data);
#endif
#if defined(CONFIG_MTD_NAND_MXC) \
|| defined(CONFIG_MTD_NAND_MXC_MODULE) \
@@ -356,6 +403,9 @@ static void __init mxc_board_init(void)
|| defined(CONFIG_MTD_NAND_MXC_V3_MODULE)
mxc_register_device(&mxc_nandv2_mtd_device, &mxc_nand_data);
#endif
+#if defined(CONFIG_PATA_FSL) || defined(CONFIG_PATA_FSL_MODULE)
+ mxc_register_device(&pata_fsl_device, &ata_data);
+#endif
#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
mxc_register_device(&smsc911x_device, &ccwmx51_smsc9118);
#endif
@@ -368,23 +418,26 @@ static void __init mxc_board_init(void)
mx5_usbh1_init();
#endif
mx5_usb_dr_init();
-#if defined(CONFIG_FB_MXC_SYNC_PANEL) || defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE)
- mxc_register_device(&lcd_pdev, plcd_platform_data);
- mxc_fb_devices[0].num_resources = ARRAY_SIZE(mxcfb_resources);
- mxc_fb_devices[0].resource = mxcfb_resources;
- mxc_register_device(&mxc_fb_devices[0], &mx51_fb_data[0]);
-// mxc_register_device(&mxc_fb_devices[1], &mx51_fb_data[1]);
-// mxc_register_device(&mxc_fb_devices[2], NULL);
-#endif
+#if defined(CONFIG_FB_MXC_SYNC_PANEL) || defined(CONFIG_FB_MXC_SYNC_PANEL_MODULE) && \
+ (defined(CONFIG_CCWMX51_DISP0) || defined(CONFIG_CCWMX51_DISP1))
+ ccwmx51_init_fb();
+#endif /* defined(CONFIG_FB_MXC_SYNC_PANEL) || ... */
#ifdef CONFIG_MXC_PMIC_MC13892
ccwmx51_init_mc13892();
/* Configure PMIC irq line */
set_irq_type(IOMUX_TO_GPIO(MX51_PIN_GPIO1_5), IRQ_TYPE_EDGE_BOTH);
#endif
- ccwmx51js_add_device_buttons();
- ccwmx51js_gpio_leds(ccwmx51js_leds, ARRAY_SIZE(ccwmx51js_leds));
+#ifdef CONFIG_SYSFS
+ ccwmx51_create_sysfs_entries();
+#endif
+#ifdef CONFIG_CCWMX51_SECOND_TOUCH
+ ccwmx51_init_2nd_touch();
+#endif
+#if defined(CONFIG_KEYBOARD_GPIO)
+ mxc_register_device(&ccwmx51js_keys_gpio, &ccwmx51js_gpio_key_info);
+#endif
pm_power_off = mxc_power_off;
}
@@ -394,9 +447,9 @@ static void __init ccwmx51_timer_init(void)
/* Change the CPU voltages for TO2*/
if (cpu_is_mx51_rev(CHIP_REV_2_0) <= 1) {
- cpu_wp_auto[0].cpu_voltage = 1175000;
- cpu_wp_auto[1].cpu_voltage = 1100000;
- cpu_wp_auto[2].cpu_voltage = 1000000;
+ cpu_wp_auto_800[0].cpu_voltage = 1175000;
+ cpu_wp_auto_800[1].cpu_voltage = 1100000;
+ cpu_wp_auto_800[2].cpu_voltage = 1000000;
}
mx51_clocks_init(32768, 24000000, 22579200, 24576000);
@@ -409,14 +462,30 @@ static struct sys_timer mxc_timer = {
.init = ccwmx51_timer_init,
};
-MACHINE_START(CCWMX51JS, "ConnectCore Wi-i.MX51 on a JSK board")
+#if defined(CONFIG_MACH_CCWMX51JS)
+MACHINE_START(CCWMX51JS, "ConnectCore Wi-i.MX51"BOARD_NAME)
+ /* Maintainer: Digi International, Inc. */
+ .phys_io = AIPS1_BASE_ADDR,
+ .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+ .boot_params = PHYS_OFFSET + 0x100,
+ .fixup = fixup_mxc_board,
+ .map_io = mx5_map_io,
+ .init_irq = mx5_init_irq,
+ .init_machine = mxc_board_init,
+ .timer = &mxc_timer,
+MACHINE_END
+#endif /* CONFIG_MACH_CCWMX51JS */
+
+#if defined(CONFIG_MACH_CCMX51JS)
+MACHINE_START(CCMX51JS, "ConnectCore i.MX51"BOARD_NAME)
/* Maintainer: Digi International, Inc. */
- .phys_io = AIPS1_BASE_ADDR,
- .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
- .boot_params = PHYS_OFFSET + 0x100,
- .fixup = fixup_mxc_board,
- .map_io = mx5_map_io,
- .init_irq = mx5_init_irq,
- .init_machine = mxc_board_init,
- .timer = &mxc_timer,
+ .phys_io = AIPS1_BASE_ADDR,
+ .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+ .boot_params = PHYS_OFFSET + 0x100,
+ .fixup = fixup_mxc_board,
+ .map_io = mx5_map_io,
+ .init_irq = mx5_init_irq,
+ .init_machine = mxc_board_init,
+ .timer = &mxc_timer,
MACHINE_END
+#endif /* CONFIG_MACH_CCMX51JS */
diff --git a/arch/arm/mach-mx5/mx51_ccwmx51js_gpio.c b/arch/arm/mach-mx5/mx51_ccwmx51js_gpio.c
index 51b9301a3547..b626605bd8fa 100644
--- a/arch/arm/mach-mx5/mx51_ccwmx51js_gpio.c
+++ b/arch/arm/mach-mx5/mx51_ccwmx51js_gpio.c
@@ -21,8 +21,7 @@
#include "iomux.h"
#include "mx51_pins.h"
-
-static void ccwmx51_mmc2_gpio_active(void);
+#include "board-ccwmx51.h"
/**
@@ -30,8 +29,8 @@ static void ccwmx51_mmc2_gpio_active(void);
*/
#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_ext_eth_pins[] = {
- {MX51_PIN_EIM_CS5, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_KEEPER | PAD_CTL_DRV_MEDIUM), },
+ {MX51_PIN_EIM_CS5, IOMUX_CONFIG_ALT0,
+ (PAD_CTL_HYS_ENABLE | PAD_CTL_PUE_KEEPER | PAD_CTL_DRV_MEDIUM), },
{MX51_PIN_EIM_OE, IOMUX_CONFIG_ALT0,},
{MX51_PIN_EIM_DA0, IOMUX_CONFIG_ALT0,},
{MX51_PIN_EIM_DA1, IOMUX_CONFIG_ALT0,},
@@ -62,7 +61,7 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_ext_eth_pins[] = {
#endif
#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE)
-static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_mmc_pins[] = {
+static struct mxc_iomux_pin_cfg ccwmx51_iomux_mmc1_pins[] = {
/* SDHC1*/
{
MX51_PIN_SD1_CMD, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION,
@@ -94,11 +93,49 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_mmc_pins[] = {
(PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH |
PAD_CTL_47K_PU | PAD_CTL_SRE_FAST),
},
+#ifdef CONFIG_JSCCWMX51_V1
{
MX51_PIN_GPIO1_0, IOMUX_CONFIG_GPIO | IOMUX_CONFIG_SION,
(PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU),
},
+#endif
+};
+
+#ifdef CONFIG_MACH_CCWMX51JS
+/* IOMUX settings, for the wireless interface on Wi-i.MX51 module */
+#define SD2_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_DRV_VOT_HIGH | \
+ PAD_CTL_22K_PU | PAD_CTL_PUE_PULL | \
+ PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST)
+static struct mxc_iomux_pin_cfg ccwmx51_iomux_mmc2_pins[] = {
+ /* SDHC2*/
+ {
+ MX51_PIN_SD2_CMD, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION,
+ SD2_PAD_CFG,
+ },
+ {
+ MX51_PIN_SD2_CLK, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION,
+ SD2_PAD_CFG,
+ },
+ {
+ MX51_PIN_SD2_DATA0, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION,
+ SD2_PAD_CFG,
+ },
+ {
+ MX51_PIN_SD2_DATA1, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION,
+ SD2_PAD_CFG,
+ },
+ {
+ MX51_PIN_SD2_DATA2, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION,
+ SD2_PAD_CFG,
+ },
+ {
+ MX51_PIN_SD2_DATA3, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION,
+ SD2_PAD_CFG,
+ },
+};
+#endif
+static struct mxc_iomux_pin_cfg ccwmx51_iomux_mmc3_pins[] = {
/* SDHC3*/
{
MX51_PIN_NANDF_RDY_INT, IOMUX_CONFIG_ALT5 | IOMUX_CONFIG_SION,
@@ -137,6 +174,56 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_mmc_pins[] = {
(PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU),
},
};
+
+void gpio_sdhc_active(int interface)
+{
+ int i;
+
+ switch (interface) {
+ case 0:
+ for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_mmc1_pins); i++) {
+ mxc_request_iomux(ccwmx51_iomux_mmc1_pins[i].pin,
+ ccwmx51_iomux_mmc1_pins[i].mux_mode);
+ if (ccwmx51_iomux_mmc1_pins[i].pad_cfg)
+ mxc_iomux_set_pad(ccwmx51_iomux_mmc1_pins[i].pin,
+ ccwmx51_iomux_mmc1_pins[i].pad_cfg);
+ if (ccwmx51_iomux_mmc1_pins[i].in_select)
+ mxc_iomux_set_input(ccwmx51_iomux_mmc1_pins[i].in_select,
+ ccwmx51_iomux_mmc1_pins[i].in_mode);
+ }
+ break;
+ case 1:
+#ifdef CONFIG_MACH_CCWMX51JS
+ for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_mmc2_pins); i++) {
+ mxc_request_iomux(ccwmx51_iomux_mmc2_pins[i].pin,
+ ccwmx51_iomux_mmc2_pins[i].mux_mode);
+ if (ccwmx51_iomux_mmc2_pins[i].pad_cfg)
+ mxc_iomux_set_pad(ccwmx51_iomux_mmc2_pins[i].pin,
+ ccwmx51_iomux_mmc2_pins[i].pad_cfg);
+ if (ccwmx51_iomux_mmc2_pins[i].in_select)
+ mxc_iomux_set_input(ccwmx51_iomux_mmc2_pins[i].in_select,
+ ccwmx51_iomux_mmc2_pins[i].in_mode);
+ }
+#endif
+ break;
+
+ case 2:
+ for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_mmc3_pins); i++) {
+ mxc_request_iomux(ccwmx51_iomux_mmc3_pins[i].pin,
+ ccwmx51_iomux_mmc3_pins[i].mux_mode);
+ if (ccwmx51_iomux_mmc3_pins[i].pad_cfg)
+ mxc_iomux_set_pad(ccwmx51_iomux_mmc3_pins[i].pin,
+ ccwmx51_iomux_mmc3_pins[i].pad_cfg);
+ if (ccwmx51_iomux_mmc3_pins[i].in_select)
+ mxc_iomux_set_input(ccwmx51_iomux_mmc3_pins[i].in_select,
+ ccwmx51_iomux_mmc3_pins[i].in_mode);
+ }
+ break;
+ }
+}
+EXPORT_SYMBOL(gpio_sdhc_active);
+void gpio_sdhc_inactive(int module) {}
+EXPORT_SYMBOL(gpio_sdhc_inactive);
#endif
#if defined(CONFIG_USB_EHCI_ARC_H1) || defined(CONFIG_USB_EHCI_ARC_H1_MODULE)
@@ -202,122 +289,218 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_usbh1_pins[] = {
PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE),
},
{ /* USBH PHY RESET */
- MX51_PIN_DISPB2_SER_RS, IOMUX_CONFIG_GPIO,
+ MX51_PIN_DISPB2_SER_RS, IOMUX_CONFIG_ALT4,
(PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_47K_PU |
PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE),
+ MUX_IN_GPIO3_IPP_IND_G_IN_8_SELECT_INPUT, INPUT_CTL_PATH1
},
};
#endif
#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[] = {
- { /* DISP1 DAT0 */
+#if defined(CONFIG_CCWMX51_DISP0)
+#define DISP1_PAD0 (PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST)
+static struct mxc_iomux_pin_cfg ccwmx51_iomux_video1_pins[] = {
+ { /* DISP1 DAT0 */
MX51_PIN_DISP1_DAT0, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT1 */
MX51_PIN_DISP1_DAT1, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT2 */
MX51_PIN_DISP1_DAT2, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT3 */
MX51_PIN_DISP1_DAT3, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT4 */
MX51_PIN_DISP1_DAT4, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT5 */
MX51_PIN_DISP1_DAT5, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT6 */
MX51_PIN_DISP1_DAT6, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT7 */
MX51_PIN_DISP1_DAT7, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT8 */
MX51_PIN_DISP1_DAT8, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT9 */
MX51_PIN_DISP1_DAT9, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT10 */
MX51_PIN_DISP1_DAT10, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT11 */
MX51_PIN_DISP1_DAT11, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT12 */
MX51_PIN_DISP1_DAT12, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT13 */
MX51_PIN_DISP1_DAT13, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT14 */
MX51_PIN_DISP1_DAT14, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT15 */
MX51_PIN_DISP1_DAT15, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT16 */
MX51_PIN_DISP1_DAT16, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT17 */
MX51_PIN_DISP1_DAT17, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT18 */
MX51_PIN_DISP1_DAT18, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT19 */
MX51_PIN_DISP1_DAT19, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT20 */
MX51_PIN_DISP1_DAT20, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ DISP1_PAD0,
},
{ /* DISP1 DAT21 */
- MX51_PIN_DISP1_DAT21, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
- },
- { /* DISP1 DAT22 */
- MX51_PIN_DISP1_DAT22, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
+ MX51_PIN_DISP1_DAT21, IOMUX_CONFIG_ALT0,
+ DISP1_PAD0,
+ },
+#if !defined(CONFIG_CCWMX51_DISP1)
+ { /* DISP1 DAT22 */
+ MX51_PIN_DISP1_DAT22, IOMUX_CONFIG_ALT0,
+ DISP1_PAD0,
},
{ /* DISP1 DAT23 */
- MX51_PIN_DISP1_DAT23, IOMUX_CONFIG_ALT0,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
- },
- { /* LCD1 Power Enable, as gpio */
- MX51_PIN_DI1_PIN11, IOMUX_CONFIG_GPIO,
- (PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_47K_PU |
- PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE),
- },
+ MX51_PIN_DISP1_DAT23, IOMUX_CONFIG_ALT0,
+ DISP1_PAD0,
+ },
+#endif
};
#endif
+#if defined(CONFIG_CCWMX51_DISP1)
+#define DISP2_PAD0 (PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | PAD_CTL_SRE_FAST)
+static struct mxc_iomux_pin_cfg ccwmx51_iomux_video2_pins[] = {
+ /* This interface can be enabled only if the FEC interface is disabled */
+ { /* DISP2 DAT0 */
+ MX51_PIN_DISP2_DAT0, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT1 */
+ MX51_PIN_DISP2_DAT1, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT2 */
+ MX51_PIN_DISP2_DAT2, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT3 */
+ MX51_PIN_DISP2_DAT3, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT4 */
+ MX51_PIN_DISP2_DAT4, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT5 */
+ MX51_PIN_DISP2_DAT5, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT6 */
+ MX51_PIN_DISP2_DAT6, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT7 */
+ MX51_PIN_DISP2_DAT7, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT8 */
+ MX51_PIN_DISP2_DAT8, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT9 */
+ MX51_PIN_DISP2_DAT9, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT10 */
+ MX51_PIN_DISP2_DAT10, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT11 */
+ MX51_PIN_DISP2_DAT11, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT12 */
+ MX51_PIN_DISP2_DAT12, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT13 */
+ MX51_PIN_DISP2_DAT13, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT14 */
+ MX51_PIN_DISP2_DAT14, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DAT15 */
+ MX51_PIN_DISP2_DAT15, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 16 (also DISP1 DAT22) */
+ MX51_PIN_DISP1_DAT22, IOMUX_CONFIG_ALT5,
+ DISP2_PAD0,
+ },
+ { /* DISP2 17 (also DISP1 DAT23) */
+ MX51_PIN_DISP1_DAT23, IOMUX_CONFIG_ALT5,
+ DISP2_PAD0,
+ },
+ { /* DISP2 HSYNC */
+ MX51_PIN_DI2_PIN2, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 VSYNC */
+ MX51_PIN_DI2_PIN3, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 PCLK */
+ MX51_PIN_DI2_DISP_CLK, IOMUX_CONFIG_ALT0,
+ DISP2_PAD0,
+ },
+ { /* DISP2 DRDY */
+ MX51_PIN_DI_GP4, IOMUX_CONFIG_ALT4,
+ DISP2_PAD0,
+ },
+};
+#endif
+#endif
+
#if defined(CONFIG_I2C_MXC) || defined(CONFIG_I2C_MXC_MODULE)
static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_i2c_pins[] = {
-#ifdef CONFIG_I2C_MXC_SELECT1
+#if defined (CONFIG_I2C_MXC_SELECT1)
{
MX51_PIN_SD2_CMD, IOMUX_CONFIG_ALT1 | IOMUX_CONFIG_SION,
(PAD_CTL_SRE_FAST | PAD_CTL_ODE_OPENDRAIN_ENABLE | PAD_CTL_HYS_ENABLE |
@@ -376,28 +559,6 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_devices_pins[] = {
PAD_CTL_100K_PU | PAD_CTL_PKE_ENABLE | PAD_CTL_SRE_FAST),
},
#endif
- /* Push Buttons */
-#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
- { /* Button 1 */
- MX51_PIN_GPIO1_8, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
- },
- { /* Button 2 */
- MX51_PIN_GPIO1_1, IOMUX_CONFIG_ALT1 | IOMUX_CONFIG_SION,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
- },
-#endif
- /* LEDs */
-#if defined(CONFIG_NEW_LEDS)
- { /* LED1 */
- MX51_PIN_NANDF_RB2, IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
- },
- { /* LED2 */
- MX51_PIN_NANDF_RB1, IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION,
- (PAD_CTL_HYS_NONE | PAD_CTL_DRV_LOW | PAD_CTL_SRE_FAST),
- },
-#endif
};
#if defined(CONFIG_SND_SOC_WM8753) || defined(CONFIG_SND_SOC_WM8753_MODULE)
@@ -429,6 +590,93 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_audio_pins[] = {
};
#endif
+#if defined CONFIG_VIDEO_MXC_IPU_CAMERA
+static struct mxc_iomux_pin_cfg __initdata ccwmx51_camera_pins[] = {
+ /* CSI0 camera interface 1 */
+ {
+ MX51_PIN_CSI1_D12, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI1_D13, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI1_D14, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI1_D15, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI1_D16, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI1_D17, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI1_D18, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI1_D19, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI1_VSYNC, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION,
+ (PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW),
+ },
+ {
+ MX51_PIN_CSI1_HSYNC, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION,
+ (PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW),
+ },
+ /* Configure GPIO3_13 as RESET for camera 1 */
+ {
+ MX51_PIN_CSI1_D9, IOMUX_CONFIG_ALT3,
+ (PAD_CTL_HYS_NONE | PAD_CTL_DRV_MEDIUM | PAD_CTL_SRE_FAST),
+ },
+ /* CSI2 camera interface 2 */
+ {
+ MX51_PIN_CSI2_D12, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI2_D13, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI2_D14, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI2_D15, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI2_D16, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI2_D17, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI2_D18, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI2_D19, IOMUX_CONFIG_ALT0, PAD_CTL_HYS_NONE,
+ },
+ {
+ MX51_PIN_CSI2_VSYNC, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION,
+ (PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW),
+ },
+ {
+ MX51_PIN_CSI2_HSYNC, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION,
+ (PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW),
+ },
+ {
+ MX51_PIN_CSI2_PIXCLK, IOMUX_CONFIG_ALT0,
+ (PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW),
+ },
+ /* Configure GPIO3_7 as RESET for camera 2 */
+ {
+ MX51_PIN_DISPB2_SER_CLK, IOMUX_CONFIG_ALT4,
+ (PAD_CTL_HYS_NONE | PAD_CTL_DRV_MEDIUM | PAD_CTL_SRE_FAST | IOMUX_CONFIG_SION),
+ MUX_IN_GPIO3_IPP_IND_G_IN_7_SELECT_INPUT,
+ INPUT_CTL_PATH1
+ },
+};
+#endif /* #if defined CONFIG_VIDEO_MXC_IPU_CAMERA */
+
#if defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE)
static struct mxc_iomux_pin_cfg __initdata ccwmx51_cspi_pins[] = {
#ifdef CONFIG_SPI_MXC_SELECT1
@@ -453,6 +701,29 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_cspi_pins[] = {
(PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_47K_PU |
PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE),
},
+
+#if defined(CONFIG_JSCCWMX51_V1)
+ { /* TS CS for LCD1 on CCWMX51 EAK */
+ MX51_PIN_DI1_D1_CS, IOMUX_CONFIG_ALT4,
+ (PAD_CTL_SRE_SLOW | PAD_CTL_DRV_MEDIUM | PAD_CTL_ODE_OPENDRAIN_NONE |
+ PAD_CTL_PUE_KEEPER | PAD_CTL_HYS_NONE),
+ MUX_IN_GPIO3_IPP_IND_G_IN_4_SELECT_INPUT,INPUT_CTL_PATH1
+ },
+ { /* TS CS for LCD2 on CCWMX51 EAK */
+ MX51_PIN_CSPI1_RDY, IOMUX_CONFIG_ALT3,
+ (PAD_CTL_SRE_SLOW | PAD_CTL_DRV_MEDIUM | PAD_CTL_ODE_OPENDRAIN_NONE |
+ PAD_CTL_PUE_PULL | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_NONE),
+ MUX_IN_AUDMUX_P4_INPUT_TXFS_AMX_SELECT_INPUT,INPUT_CTL_PATH1
+ },
+#else
+ { /* TS CS for LCD1 and LCD2 on CCWMX51 JSK */
+ MX51_PIN_CSPI1_RDY, IOMUX_CONFIG_ALT3,
+ (PAD_CTL_SRE_SLOW | PAD_CTL_DRV_MEDIUM | PAD_CTL_ODE_OPENDRAIN_NONE |
+ PAD_CTL_PUE_PULL | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_NONE),
+ MUX_IN_AUDMUX_P4_INPUT_TXFS_AMX_SELECT_INPUT,INPUT_CTL_PATH1
+ },
+#endif
+
#ifdef CONFIG_SPI_MXC_SELECT1_SS1
{ /* SS1 */
MX51_PIN_CSPI1_SS1, IOMUX_CONFIG_GPIO,
@@ -461,7 +732,7 @@ static struct mxc_iomux_pin_cfg __initdata ccwmx51_cspi_pins[] = {
},
#endif
#endif
-#ifdef CONFIG_SPI_MXC_SELECT2
+#if defined(CONFIG_SPI_MXC_SELECT2) && (!defined(CONFIG_PATA_FSL) && !defined(CONFIG_PATA_FSL_MODULE))
/* ECSPI2 */
{ /* SCLK */
MX51_PIN_NANDF_RB2, IOMUX_CONFIG_ALT2,
@@ -534,17 +805,37 @@ void ccwmx51_gpio_spi_chipselect_active(int busnum, int ssb_pol, int chipselect)
{
u8 mask = 0x1 << (chipselect - 1);
+ /* Deassert/Assert the different CS lines for the different buses */
switch (busnum) {
case 1:
switch (chipselect) {
case 0x1:
+ gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS1),
+ (ssb_pol & mask) ? 0 : 1);
+#ifdef CONFIG_CCWMX51_SECOND_TOUCH
+ gpio_set_value(IOMUX_TO_GPIO(SECOND_TS_SPI_SS_PIN), 1);
+#endif
gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS0),
(ssb_pol & mask) ? 1 : 0);
break;
case 0x2:
+ gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS0),
+ (ssb_pol & mask) ? 0 : 1);
+#ifdef CONFIG_CCWMX51_SECOND_TOUCH
+ gpio_set_value(IOMUX_TO_GPIO(SECOND_TS_SPI_SS_PIN), 1);
+#endif
gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS1),
(ssb_pol & mask) ? 1 : 0);
break;
+#ifdef CONFIG_CCWMX51_SECOND_TOUCH
+ case 0x4:
+ gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS0),
+ (ssb_pol & mask) ? 0 : 1);
+ gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS1),
+ (ssb_pol & mask) ? 0 : 1);
+ gpio_set_value(IOMUX_TO_GPIO(SECOND_TS_SPI_SS_PIN), 0);
+ break;
+#endif
default:
break;
}
@@ -573,6 +864,11 @@ void ccwmx51_gpio_spi_chipselect_inactive(int busnum, int ssb_pol,
gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSPI1_SS1),
(ssb_pol & mask) ? 0 : 1);
break;
+#ifdef CONFIG_CCWMX51_SECOND_TOUCH
+ case 0x4:
+ gpio_set_value(IOMUX_TO_GPIO(SECOND_TS_SPI_SS_PIN), 1);
+ break;
+#endif
default:
break;
}
@@ -581,20 +877,159 @@ void ccwmx51_gpio_spi_chipselect_inactive(int busnum, int ssb_pol,
case 3:
default:
break;
- }
+ }
}
EXPORT_SYMBOL(ccwmx51_gpio_spi_chipselect_inactive);
-
#endif /* defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE) */
-void __init ccwmx51_io_init(void)
+#if defined(CONFIG_PATA_FSL) || defined(CONFIG_PATA_FSL_MODULE)
+static struct mxc_iomux_pin_cfg ata_iomux_pins[] = {
+ {
+ MX51_PIN_NANDF_ALE, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_CS2, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_CS3, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_CS4, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_CS5, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_CS6, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_RE_B, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_WE_B, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_CLE, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_RB0, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_WP_B, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_GPIO_NAND, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_RB1, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D0, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D1, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D2, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D3, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D4, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D5, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D6, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D7, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D8, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D9, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D10, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D11, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D12, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D13, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D14, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+ {
+ MX51_PIN_NANDF_D15, IOMUX_CONFIG_ALT1,
+ (PAD_CTL_DRV_HIGH | PAD_CTL_DRV_VOT_HIGH),
+ },
+};
+
+void gpio_ata_active(void)
{
int i;
+ for (i = 0; i < ARRAY_SIZE(ata_iomux_pins); i++) {
+ mxc_request_iomux(ata_iomux_pins[i].pin,
+ ata_iomux_pins[i].mux_mode);
+ if (ata_iomux_pins[i].pad_cfg)
+ mxc_iomux_set_pad(ata_iomux_pins[i].pin,
+ ata_iomux_pins[i].pad_cfg);
+ if (ata_iomux_pins[i].in_select)
+ mxc_iomux_set_input(ata_iomux_pins[i].in_select,
+ ata_iomux_pins[i].in_mode);
+ }
+}
+EXPORT_SYMBOL(gpio_ata_active);
+void gpio_ata_inactive(void) {}
+EXPORT_SYMBOL(gpio_ata_inactive);
+#endif /* CONFIG_PATA_FSL || CONFIG_PATA_FSL_MODULE */
+
+void __init ccwmx51_io_init(void)
+{
+ int i;
+
#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
- for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_ext_eth_pins); i++) {
- mxc_request_iomux(ccwmx51_iomux_ext_eth_pins[i].pin,
- ccwmx51_iomux_ext_eth_pins[i].mux_mode);
+ for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_ext_eth_pins); i++) {
+ mxc_request_iomux(ccwmx51_iomux_ext_eth_pins[i].pin,
+ ccwmx51_iomux_ext_eth_pins[i].mux_mode);
if (ccwmx51_iomux_ext_eth_pins[i].pad_cfg)
mxc_iomux_set_pad(ccwmx51_iomux_ext_eth_pins[i].pin,
ccwmx51_iomux_ext_eth_pins[i].pad_cfg);
@@ -604,17 +1039,40 @@ void __init ccwmx51_io_init(void)
}
#endif
-#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE)
- for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_mmc_pins); i++) {
- mxc_request_iomux(ccwmx51_iomux_mmc_pins[i].pin,
- ccwmx51_iomux_mmc_pins[i].mux_mode);
- if (ccwmx51_iomux_mmc_pins[i].pad_cfg)
- mxc_iomux_set_pad(ccwmx51_iomux_mmc_pins[i].pin,
- ccwmx51_iomux_mmc_pins[i].pad_cfg);
- if (ccwmx51_iomux_mmc_pins[i].in_select)
- mxc_iomux_set_input(ccwmx51_iomux_mmc_pins[i].in_select,
- ccwmx51_iomux_mmc_pins[i].in_mode);
+#if defined CONFIG_VIDEO_MXC_IPU_CAMERA
+ for (i = 0; i < ARRAY_SIZE(ccwmx51_camera_pins); i++) {
+ mxc_request_iomux(ccwmx51_camera_pins[i].pin,
+ ccwmx51_camera_pins[i].mux_mode);
+ if (ccwmx51_camera_pins[i].pad_cfg)
+ mxc_iomux_set_pad(ccwmx51_camera_pins[i].pin,
+ ccwmx51_camera_pins[i].pad_cfg);
+ if (ccwmx51_camera_pins[i].in_select)
+ mxc_iomux_set_input(ccwmx51_camera_pins[i].in_select,
+ ccwmx51_camera_pins[i].in_mode);
}
+
+ /* Configure non muxed pins */
+ mxc_iomux_set_pad(MX51_PIN_CSI1_PIXCLK,PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW);
+ mxc_iomux_set_pad(MX51_PIN_CSI2_PIXCLK,PAD_CTL_HYS_NONE | PAD_CTL_SRE_SLOW);
+ mxc_iomux_set_pad(MX51_PIN_CSI1_MCLK,PAD_CTL_DRV_HIGH | PAD_CTL_SRE_SLOW);
+
+ /* Camera 1 reset */
+ gpio_request(IOMUX_TO_GPIO(MX51_PIN_CSI1_D9), "gpio3_13");
+ gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_CSI1_D9), 0);
+ // Take camera out of reset
+ gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSI1_D9), 0);
+ msleep(100);
+ gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSI1_D9), 1);
+ msleep(100);
+
+ /* Camera 2 reset */
+ gpio_request(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_CLK), "gpio3_7");
+ gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_CLK), 0);
+ // Take camera out of reset
+ gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_CLK), 0);
+ msleep(100);
+ gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_CLK), 1);
+ msleep(100);
#endif
#if defined(CONFIG_USB_EHCI_ARC_H1) || defined(CONFIG_USB_EHCI_ARC_H1_MODULE)
@@ -630,25 +1088,9 @@ void __init ccwmx51_io_init(void)
}
#endif
-#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);
- 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);
- }
- /* LCD Power Enable */
- gpio_request(IOMUX_TO_GPIO(MX51_PIN_DI1_PIN11), "gpio3_0");
- gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DI1_PIN11), 0);
-#endif
-
#if defined(CONFIG_I2C_MXC) || defined(CONFIG_I2C_MXC_MODULE)
- for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_i2c_pins); i++) {
- mxc_request_iomux(ccwmx51_iomux_i2c_pins[i].pin,
+ for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_i2c_pins); i++) {
+ mxc_request_iomux(ccwmx51_iomux_i2c_pins[i].pin,
ccwmx51_iomux_i2c_pins[i].mux_mode);
if (ccwmx51_iomux_i2c_pins[i].pad_cfg)
mxc_iomux_set_pad(ccwmx51_iomux_i2c_pins[i].pin,
@@ -695,16 +1137,18 @@ void __init ccwmx51_io_init(void)
#endif
#ifndef CONFIG_SPI_MXC_SELECT2
- /* Configure as GPIO to be used to read LED status */
- mxc_config_iomux(MX51_PIN_NANDF_RB2,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
- mxc_iomux_set_pad(MX51_PIN_NANDF_RB2,PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU);
- mxc_config_iomux(MX51_PIN_NANDF_RB1,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
- mxc_iomux_set_pad(MX51_PIN_NANDF_RB1,PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU);
+ /* Configure as GPIO to be used to read LED status */
+ mxc_config_iomux(MX51_PIN_NANDF_RB2,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
+ mxc_iomux_set_pad(MX51_PIN_NANDF_RB2,PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU);
+#if !defined(CONFIG_PATA_FSL) && !defined(CONFIG_PATA_FSL_MODULE)
+ mxc_config_iomux(MX51_PIN_NANDF_RB1,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
+ mxc_iomux_set_pad(MX51_PIN_NANDF_RB1,PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU);
+#endif /* !defined(CONFIG_PATA_FSL) && !defined(CONFIG_PATA_FSL_MODULE) */
#endif
#endif
- for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_devices_pins); i++) {
+ for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_devices_pins); i++) {
mxc_request_iomux(ccwmx51_iomux_devices_pins[i].pin,
ccwmx51_iomux_devices_pins[i].mux_mode);
if (ccwmx51_iomux_devices_pins[i].pad_cfg)
@@ -727,67 +1171,91 @@ void __init ccwmx51_io_init(void)
gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_DISPB2_SER_RS), 1);
#endif
-#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE)
- /* For the wireless module */
- ccwmx51_mmc2_gpio_active();
+ /* Configure user key 1 as GPIO */
+#if defined(CONFIG_JSCCWMX51_V2)
+ mxc_config_iomux(MX51_PIN_DISPB2_SER_DIO,IOMUX_CONFIG_ALT4 | IOMUX_CONFIG_SION);
+ mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_6_SELECT_INPUT,INPUT_CTL_PATH1);
#endif
-}
-#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE)
-/* IOMUX settings, for the wireless interface */
-static struct mxc_iomux_pin_cfg __initdata ccwmx51_iomux_mmc2_pins[] = {
- /* SDHC2*/
- {
- MX51_PIN_SD2_CMD, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION,
- (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH |
- PAD_CTL_47K_PU | PAD_CTL_SRE_FAST),
- },
- {
- MX51_PIN_SD2_CLK, IOMUX_CONFIG_ALT0,
- (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH |
- PAD_CTL_47K_PU | PAD_CTL_SRE_FAST),
- },
- {
- MX51_PIN_SD2_DATA0, IOMUX_CONFIG_ALT0,
- (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH |
- PAD_CTL_47K_PU | PAD_CTL_SRE_FAST),
- },
- {
- MX51_PIN_SD2_DATA1, IOMUX_CONFIG_ALT0,
- (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH |
- PAD_CTL_47K_PU | PAD_CTL_SRE_FAST),
- },
- {
- MX51_PIN_SD2_DATA2, IOMUX_CONFIG_ALT0,
- (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH |
- PAD_CTL_47K_PU | PAD_CTL_SRE_FAST),
- },
- {
- MX51_PIN_SD2_DATA3, IOMUX_CONFIG_ALT0,
- (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH |
- PAD_CTL_47K_PU | PAD_CTL_SRE_FAST),
- },
-};
+ /* Configure Digital IO as GPIO */
+#if defined(CONFIG_JSCCWMX51_V1)
+#if !defined(CONFIG_PATA_FSL) && !defined(CONFIG_PATA_FSL_MODULE)
+ mxc_config_iomux(MX51_PIN_NANDF_CS4,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
+ mxc_config_iomux(MX51_PIN_NANDF_CS5,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
+ mxc_config_iomux(MX51_PIN_NANDF_CS6,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
+#endif
+#if !defined(CONFIG_MMC_IMX_ESDHCI) && !defined(CONFIG_MMC_IMX_ESDHCI_MODULE)
+ mxc_config_iomux(MX51_PIN_NANDF_CS7,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
+#endif
-static void ccwmx51_mmc2_gpio_active(void)
-{
- int i;
+ mxc_config_iomux(MX51_PIN_DISPB2_SER_DIN,IOMUX_CONFIG_ALT4 | IOMUX_CONFIG_SION);
+ mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_5_SELECT_INPUT,INPUT_CTL_PATH1);
+ mxc_config_iomux(MX51_PIN_DISPB2_SER_DIO,IOMUX_CONFIG_ALT4 | IOMUX_CONFIG_SION);
+ mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_6_SELECT_INPUT,INPUT_CTL_PATH1);
+#if !defined (CONFIG_VIDEO_MXC_IPU_CAMERA)
+ mxc_config_iomux(MX51_PIN_DISPB2_SER_CLK,IOMUX_CONFIG_ALT4 | IOMUX_CONFIG_SION);
+ mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_7_SELECT_INPUT,INPUT_CTL_PATH1);
+#endif
+#if !defined(CONFIG_USB_EHCI_ARC_H1) && !defined(CONFIG_USB_EHCI_ARC_H1_MODULE)
+ mxc_config_iomux(MX51_PIN_DISPB2_SER_RS,IOMUX_CONFIG_ALT4 | IOMUX_CONFIG_SION);
+ mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_8_SELECT_INPUT,INPUT_CTL_PATH1);
+#endif
+#endif
+
+#if defined(CONFIG_JSCCWMX51_V2)
+#if !defined (CONFIG_SPI_MXC_SELECT2)
+ mxc_config_iomux(MX51_PIN_NANDF_RB3,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
+#endif
+
+#if !defined(CONFIG_PATA_FSL) && !defined(CONFIG_PATA_FSL_MODULE)
+ mxc_config_iomux(MX51_PIN_NANDF_CS2,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
+ mxc_config_iomux(MX51_PIN_NANDF_CS4,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
+ mxc_config_iomux(MX51_PIN_NANDF_CS5,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
+ mxc_config_iomux(MX51_PIN_NANDF_CS6,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
+#endif
+
+#if !defined(CONFIG_SPI_MXC_SELECT2) || (!defined(CONFIG_PATA_FSL) && !defined(CONFIG_PATA_FSL_MODULE))
+ mxc_config_iomux(MX51_PIN_NANDF_RB1,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
+ mxc_config_iomux(MX51_PIN_NANDF_RB2,IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION);
+#endif
+ mxc_config_iomux(MX51_PIN_DISPB2_SER_DIO,IOMUX_CONFIG_ALT4 | IOMUX_CONFIG_SION);
+ mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_6_SELECT_INPUT,INPUT_CTL_PATH1);
+#endif
- for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_mmc2_pins); i++) {
- mxc_request_iomux(ccwmx51_iomux_mmc2_pins[i].pin,
- ccwmx51_iomux_mmc2_pins[i].mux_mode);
- if (ccwmx51_iomux_mmc2_pins[i].pad_cfg)
- mxc_iomux_set_pad(ccwmx51_iomux_mmc2_pins[i].pin,
- ccwmx51_iomux_mmc2_pins[i].pad_cfg);
- if (ccwmx51_iomux_mmc2_pins[i].in_select)
- mxc_iomux_set_input(ccwmx51_iomux_mmc2_pins[i].in_select,
- ccwmx51_iomux_mmc2_pins[i].in_mode);
- }
}
-void ccwmx51_mmc2_gpio_inactive(void)
+#ifdef CONFIG_CCWMX51_SECOND_TOUCH
+void ccwmx51_2nd_touch_gpio_init(void)
{
+ /* Second touch interface interrupt line */
+ mxc_request_iomux(SECOND_TS_IRQ_PIN, IOMUX_CONFIG_GPIO);
+ mxc_iomux_set_pad(SECOND_TS_IRQ_PIN, PAD_CTL_SRE_FAST | PAD_CTL_HYS_ENABLE);
+ mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_3_SELECT_INPUT, INPUT_CTL_PATH1);
+
+ /* SECOND_TS_SPI_SS_PIN depends on configuration, check board-ccwmx51 to see options */
+ mxc_request_iomux(SECOND_TS_SPI_SS_PIN, IOMUX_CONFIG_GPIO);
+ mxc_iomux_set_pad(SECOND_TS_SPI_SS_PIN, PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH |
+ PAD_CTL_47K_PU | PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE);
+
+ /* Configure the Slave Select signal as gpio, to workaround a silicon errata */
+ gpio_request(IOMUX_TO_GPIO(SECOND_TS_SPI_SS_PIN), "ts2_spi_ss");
+ gpio_direction_output(IOMUX_TO_GPIO(SECOND_TS_SPI_SS_PIN), 1);
+ gpio_set_value(IOMUX_TO_GPIO(SECOND_TS_SPI_SS_PIN), 1);
+
+ /* Configure 2nd touch interrupt line */
+ gpio_request(IOMUX_TO_GPIO(SECOND_TS_IRQ_PIN), "ts2_irq");
+ gpio_direction_input(IOMUX_TO_GPIO(SECOND_TS_IRQ_PIN));
+
+ /**
+ * Configure gpio line to detect which touch is connected to each
+ * display interface
+ */
+ mxc_config_iomux(MX51_PIN_DI1_D1_CS, IOMUX_CONFIG_GPIO);
+ mxc_iomux_set_pad(MX51_PIN_DI1_D1_CS, PAD_CTL_SRE_FAST | PAD_CTL_HYS_ENABLE);
+ mxc_iomux_set_input(MUX_IN_GPIO3_IPP_IND_G_IN_4_SELECT_INPUT, INPUT_CTL_PATH1);
}
+#else
+void ccwmx51_2nd_touch_gpio_init(void) {}
#endif
#if defined(CONFIG_SERIAL_MXC) || defined(CONFIG_SERIAL_MXC_MODULE)
@@ -808,8 +1276,24 @@ void gpio_uart_active(int port, int no_irda)
mxc_iomux_set_pad(MX51_PIN_UART1_TXD, SERIAL_PORT_PAD);
mxc_iomux_set_input(MUX_IN_UART1_IPP_UART_RXD_MUX_SELECT_INPUT, INPUT_CTL_PATH0);
- /* TODO enable CTS/RTS if selected */
-#endif
+#if defined(CONFIG_UART1_CTS_RTS_ENABLED) || defined(CONFIG_UART1_FULL_UART_ENABLED)
+ mxc_request_iomux(MX51_PIN_UART1_CTS, IOMUX_CONFIG_ALT0);
+ mxc_request_iomux(MX51_PIN_UART1_RTS, IOMUX_CONFIG_ALT0);
+ mxc_iomux_set_pad(MX51_PIN_UART1_CTS, SERIAL_PORT_PAD);
+ mxc_iomux_set_pad(MX51_PIN_UART1_RTS, SERIAL_PORT_PAD);
+ mxc_iomux_set_input(MUX_IN_UART1_IPP_UART_RTS_B_SELECT_INPUT, INPUT_CTL_PATH0);
+#endif /* CONFIG_UART1_CTS_RTS_ENABLED */
+#ifdef CONFIG_UART1_FULL_UART_ENABLED
+ mxc_request_iomux(MX51_PIN_KEY_COL5, IOMUX_CONFIG_ALT1); /* DCD */
+ mxc_request_iomux(MX51_PIN_KEY_COL4, IOMUX_CONFIG_ALT1); /* RI */
+ mxc_request_iomux(MX51_PIN_UART3_TXD, IOMUX_CONFIG_ALT0); /* DSR */
+ mxc_request_iomux(MX51_PIN_UART3_RXD, IOMUX_CONFIG_ALT0); /* DTR */
+ mxc_iomux_set_pad(MX51_PIN_KEY_COL5, SERIAL_PORT_PAD);
+ mxc_iomux_set_pad(MX51_PIN_KEY_COL4, SERIAL_PORT_PAD);
+ mxc_iomux_set_pad(MX51_PIN_UART3_TXD, SERIAL_PORT_PAD);
+ mxc_iomux_set_pad(MX51_PIN_UART3_RXD, SERIAL_PORT_PAD);
+#endif /* CONFIG_UART1_FULL_UART_ENABLED */
+#endif /* CONFIG_UART1_ENABLED */
break;
case 1: /* UART 2 IOMUX Configs */
@@ -820,8 +1304,16 @@ void gpio_uart_active(int port, int no_irda)
mxc_iomux_set_pad(MX51_PIN_UART2_TXD, SERIAL_PORT_PAD);
mxc_iomux_set_input(MUX_IN_UART2_IPP_UART_RXD_MUX_SELECT_INPUT, INPUT_CTL_PATH2);
- /* TODO enable CTS/RTS if selected */
-#endif
+#ifdef CONFIG_UART2_CTS_RTS_ENABLED
+#if !defined(CONFIG_USB_EHCI_ARC_H1) && !defined(CONFIG_USB_EHCI_ARC_H1_MODULE)
+ mxc_request_iomux(MX51_PIN_USBH1_DATA0, IOMUX_CONFIG_ALT1); /* CTS */
+ mxc_request_iomux(MX51_PIN_USBH1_DATA3, IOMUX_CONFIG_ALT1); /* RTS */
+ mxc_iomux_set_pad(MX51_PIN_USBH1_DATA0, SERIAL_PORT_PAD);
+ mxc_iomux_set_pad(MX51_PIN_USBH1_DATA3, SERIAL_PORT_PAD);
+ mxc_iomux_set_input(MUX_IN_UART2_IPP_UART_RTS_B_SELECT_INPUT, INPUT_CTL_PATH5);
+#endif /* CONFIG_USB_EHCI_ARC_H1 && CONFIG_USB_EHCI_ARC_H1_MODULE */
+#endif /* CONFIG_UART2_CTS_RTS_ENABLED */
+#endif /* CONFIG_UART2_CTS_RTS_ENABLED */
break;
case 2: /* UART 3 IOMUX Configs */
#ifdef CONFIG_UART3_ENABLED
@@ -831,15 +1323,19 @@ void gpio_uart_active(int port, int no_irda)
mxc_iomux_set_pad(MX51_PIN_UART3_TXD, SERIAL_PORT_PAD);
mxc_iomux_set_input(MUX_IN_UART3_IPP_UART_RXD_MUX_SELECT_INPUT, INPUT_CTL_PATH4);
- /* TODO enable CTS/RTS if selected */
-#endif
+#ifdef CONFIG_UART3_CTS_RTS_ENABLED
+ mxc_request_iomux(MX51_PIN_KEY_COL5, IOMUX_CONFIG_ALT2); /* CTS */
+ mxc_request_iomux(MX51_PIN_KEY_COL4, IOMUX_CONFIG_ALT2); /* RTS */
+ mxc_iomux_set_pad(MX51_PIN_KEY_COL5, SERIAL_PORT_PAD);
+ mxc_iomux_set_pad(MX51_PIN_KEY_COL4, SERIAL_PORT_PAD);
+ mxc_iomux_set_input(MUX_IN_UART3_IPP_UART_RTS_B_SELECT_INPUT, INPUT_CTL_PATH4);
+#endif /* CONFIG_UART3_CTS_RTS_ENABLED */
+#endif /* CONFIG_UART3_ENABLED */
break;
default:
break;
}
-
}
-
#else
void gpio_uart_active(int port, int no_irda) {}
#endif
@@ -847,5 +1343,74 @@ void gpio_uart_inactive(int port, int no_irda) {}
EXPORT_SYMBOL(gpio_uart_active);
EXPORT_SYMBOL(gpio_uart_inactive);
+void gpio_video_active(int vif, u32 pad)
+{
+ int i;
+
+#if defined(CONFIG_CCWMX51_DISP0)
+ if (vif == 0) {
+ 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);
+
+ 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);
+ if (!pad)
+ mxc_iomux_set_pad(ccwmx51_iomux_video1_pins[i].pin,
+ ccwmx51_iomux_video1_pins[i].pad_cfg);
+ else
+ mxc_iomux_set_pad(ccwmx51_iomux_video1_pins[i].pin,
+ pad);
+ }
+
+ /* LCD1 Power Enable, as gpio */
+ mxc_request_iomux(MX51_PIN_DI1_PIN11, IOMUX_CONFIG_GPIO);
+ mxc_iomux_set_pad(MX51_PIN_DI1_PIN11,
+ PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_47K_PU |
+ PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE);
+ gpio_request(IOMUX_TO_GPIO(MX51_PIN_DI1_PIN11), "gpio3_0");
+ gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DI1_PIN11), 0);
+ }
+#endif
+#if defined(CONFIG_CCWMX51_DISP1)
+ if (vif == 1) {
+ for (i = 0; i < ARRAY_SIZE(ccwmx51_iomux_video2_pins); i++) {
+ mxc_request_iomux(ccwmx51_iomux_video2_pins[i].pin,
+ ccwmx51_iomux_video2_pins[i].mux_mode);
+
+ if (ccwmx51_iomux_video2_pins[i].in_select)
+ mxc_iomux_set_input(ccwmx51_iomux_video2_pins[i].in_select,
+ ccwmx51_iomux_video2_pins[i].in_mode);
+ if (!pad)
+ mxc_iomux_set_pad(ccwmx51_iomux_video2_pins[i].pin,
+ ccwmx51_iomux_video2_pins[i].pad_cfg);
+ else
+ mxc_iomux_set_pad(ccwmx51_iomux_video2_pins[i].pin,
+ pad);
+ }
+
+ /* LCD2 Power Enable, as gpio */
+#ifdef CONFIG_JSCCWMX51_V1
+ mxc_request_iomux(MX51_PIN_DI2_PIN4, IOMUX_CONFIG_ALT0);
+ mxc_iomux_set_pad(MX51_PIN_DI2_PIN4, pad);
+#else
+ mxc_request_iomux(MX51_PIN_DI1_PIN12, IOMUX_CONFIG_GPIO);
+ mxc_iomux_set_pad(MX51_PIN_DI1_PIN12,
+ PAD_CTL_SRE_FAST | PAD_CTL_DRV_HIGH | PAD_CTL_47K_PU |
+ PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_HYS_ENABLE);
+
+ gpio_request(IOMUX_TO_GPIO(MX51_PIN_DI1_PIN12), "gpio3_1");
+ gpio_direction_output(IOMUX_TO_GPIO(MX51_PIN_DI1_PIN12), 0);
+#endif
+ }
+#endif /* defined(CONFIG_CCWMX51_DISP1) */
+}
+
+void gpio_video_inactive(int vif, u32 pad)
+{
+}
+EXPORT_SYMBOL(gpio_video_active);
+EXPORT_SYMBOL(gpio_video_inactive);
diff --git a/arch/arm/mach-mx5/mx53_evk.c b/arch/arm/mach-mx5/mx53_evk.c
index 104e5f93d6e9..702d7d8912d0 100644
--- a/arch/arm/mach-mx5/mx53_evk.c
+++ b/arch/arm/mach-mx5/mx53_evk.c
@@ -36,13 +36,14 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
-#include <linux/spi/flash.h>
#include <linux/regulator/consumer.h>
#include <linux/pmic_external.h>
#include <linux/pmic_status.h>
#include <linux/ipu.h>
#include <linux/mxcfb.h>
#include <linux/pwm_backlight.h>
+#include <linux/fec.h>
+#include <linux/ahci_platform.h>
#include <mach/common.h>
#include <mach/hardware.h>
#include <asm/irq.h>
@@ -51,16 +52,52 @@
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <asm/mach/keypad.h>
+#include <asm/mach/flash.h>
#include <mach/memory.h>
#include <mach/gpio.h>
#include <mach/mmc.h>
#include <mach/mxc_dvfs.h>
-#include "board-mx53_evk.h"
-#include "iomux.h"
-#include "mx53_pins.h"
+#include <mach/iomux-mx53.h>
+
#include "crm_regs.h"
#include "devices.h"
#include "usb.h"
+#include <linux/android_pmem.h>
+#include <linux/usb/android.h>
+
+#define ARM2_SD1_CD (0*32 + 1) /* GPIO_1_1 */
+
+#define MX53_HP_DETECT (1*32 + 5) /* GPIO_2_5 */
+
+#define EVK_SD3_CD (2*32 + 11) /* GPIO_3_11 */
+#define EVK_SD3_WP (2*32 + 12) /* GPIO_3_12 */
+#define EVK_SD1_CD (2*32 + 13) /* GPIO_3_13 */
+#define EVK_SD1_WP (2*32 + 14) /* GPIO_3_14 */
+#define ARM2_OTG_VBUS (2*32 + 22) /* GPIO_3_22 */
+#define MX53_DVI_PD (2*32 + 24) /* GPIO_3_24 */
+#define EVK_TS_INT (2*32 + 26) /* GPIO_3_26 */
+#define MX53_DVI_I2C (2*32 + 28) /* GPIO_3_28 */
+#define MX53_DVI_DETECT (2*32 + 31) /* GPIO_3_31 */
+
+#define MX53_CAM_RESET (3*32 + 0) /* GPIO_4_0 */
+#define MX53_ESAI_RESET (3*32 + 2) /* GPIO_4_2 */
+#define MX53_CAN2_EN2 (3*32 + 4) /* GPIO_4_4 */
+#define MX53_12V_EN (3*32 + 5) /* GPIO_4_5 */
+#define ARM2_LCD_CONTRAST (3*32 + 20) /* GPIO_4_20 */
+
+#define MX53_DVI_RESET (4*32 + 0) /* GPIO_5_0 */
+#define EVK_USB_HUB_RESET (4*32 + 20) /* GPIO_5_20 */
+#define MX53_TVIN_PWR (4*32 + 23) /* GPIO_5_23 */
+#define MX53_CAN2_EN1 (4*32 + 24) /* GPIO_5_24 */
+#define MX53_TVIN_RESET (4*32 + 25) /* GPIO_5_25 */
+
+#define EVK_OTG_VBUS (5*32 + 6) /* GPIO_6_6 */
+
+#define EVK_FEC_PHY_RESET (6*32 + 6) /* GPIO_7_6 */
+#define EVK_USBH1_VBUS (6*32 + 8) /* GPIO_7_8 */
+#define MX53_PMIC_INT (6*32 + 11) /* GPIO_7_11 */
+#define MX53_CAN1_EN1 (6*32 + 12) /* GPIO_7_12 */
+#define MX53_CAN1_EN2 (6*32 + 13) /* GPIO_7_13 */
/*!
* @file mach-mx53/mx53_evk.c
@@ -69,11 +106,298 @@
*
* @ingroup MSL_MX53
*/
-extern void __init mx53_evk_io_init(void);
+extern int __init mx53_evk_init_mc13892(void);
extern struct cpu_wp *(*get_cpu_wp)(int *wp);
extern void (*set_num_cpu_wp)(int num);
static int num_cpu_wp = 3;
+static struct pad_desc mx53common_pads[] = {
+ MX53_PAD_EIM_WAIT__GPIO_5_0,
+
+ MX53_PAD_EIM_OE__DI1_PIN7,
+ MX53_PAD_EIM_RW__DI1_PIN8,
+
+ MX53_PAD_EIM_A25__DI0_D1_CS,
+
+ MX53_PAD_EIM_D16__CSPI1_SCLK,
+ MX53_PAD_EIM_D17__CSPI1_MISO,
+ MX53_PAD_EIM_D18__CSPI1_MOSI,
+
+ MX53_PAD_EIM_D20__SER_DISP0_CS,
+
+ MX53_PAD_EIM_D23__DI0_D0_CS,
+
+ MX53_PAD_EIM_D24__GPIO_3_24,
+ MX53_PAD_EIM_D26__GPIO_3_26,
+
+ MX53_PAD_EIM_D29__DISPB0_SER_RS,
+
+ MX53_PAD_EIM_D30__DI0_PIN11,
+ MX53_PAD_EIM_D31__DI0_PIN12,
+
+ MX53_PAD_ATA_DA_1__GPIO_7_7,
+ MX53_PAD_ATA_DATA4__GPIO_2_4,
+ MX53_PAD_ATA_DATA5__GPIO_2_5,
+ MX53_PAD_ATA_DATA6__GPIO_2_6,
+
+ MX53_PAD_SD2_CLK__SD2_CLK,
+ MX53_PAD_SD2_CMD__SD2_CMD,
+ MX53_PAD_SD2_DATA0__SD2_DAT0,
+ MX53_PAD_SD2_DATA1__SD2_DAT1,
+ MX53_PAD_SD2_DATA2__SD2_DAT2,
+ MX53_PAD_SD2_DATA3__SD2_DAT3,
+ MX53_PAD_ATA_DATA12__SD2_DAT4,
+ MX53_PAD_ATA_DATA13__SD2_DAT5,
+ MX53_PAD_ATA_DATA14__SD2_DAT6,
+ MX53_PAD_ATA_DATA15__SD2_DAT7,
+
+ MX53_PAD_CSI0_D10__UART1_TXD,
+ MX53_PAD_CSI0_D11__UART1_RXD,
+
+ MX53_PAD_ATA_BUFFER_EN__UART2_RXD,
+ MX53_PAD_ATA_DMARQ__UART2_TXD,
+ MX53_PAD_ATA_DIOR__UART2_RTS,
+ MX53_PAD_ATA_INTRQ__UART2_CTS,
+
+ MX53_PAD_ATA_CS_0__UART3_TXD,
+ MX53_PAD_ATA_CS_1__UART3_RXD,
+
+ MX53_PAD_KEY_COL0__AUD5_TXC,
+ MX53_PAD_KEY_ROW0__AUD5_TXD,
+ MX53_PAD_KEY_COL1__AUD5_TXFS,
+ MX53_PAD_KEY_ROW1__AUD5_RXD,
+
+ MX53_PAD_CSI0_D7__GPIO_5_25,
+
+ MX53_PAD_GPIO_2__MLBDAT,
+ MX53_PAD_GPIO_3__MLBCLK,
+
+ MX53_PAD_GPIO_6__MLBSIG,
+
+ MX53_PAD_GPIO_4__GPIO_1_4,
+ MX53_PAD_GPIO_7__GPIO_1_7,
+ MX53_PAD_GPIO_8__GPIO_1_8,
+
+ MX53_PAD_GPIO_10__GPIO_4_0,
+
+ MX53_PAD_KEY_COL2__TXCAN1,
+ MX53_PAD_KEY_ROW2__RXCAN1,
+
+ /* CAN1 -- EN */
+ MX53_PAD_GPIO_18__GPIO_7_13,
+ /* CAN1 -- STBY */
+ MX53_PAD_GPIO_17__GPIO_7_12,
+ /* CAN1 -- NERR */
+ MX53_PAD_GPIO_5__GPIO_1_5,
+
+ MX53_PAD_KEY_COL4__TXCAN2,
+ MX53_PAD_KEY_ROW4__RXCAN2,
+
+ /* CAN2 -- EN */
+ MX53_PAD_CSI0_D6__GPIO_5_24,
+ /* CAN2 -- STBY */
+ MX53_PAD_GPIO_14__GPIO_4_4,
+ /* CAN2 -- NERR */
+ MX53_PAD_CSI0_D4__GPIO_5_22,
+
+ MX53_PAD_GPIO_11__GPIO_4_1,
+ MX53_PAD_GPIO_12__GPIO_4_2,
+ MX53_PAD_GPIO_13__GPIO_4_3,
+ MX53_PAD_GPIO_16__GPIO_7_11,
+ MX53_PAD_GPIO_19__GPIO_4_5,
+
+ /* DI0 display clock */
+ MX53_PAD_DI0_DISP_CLK__DI0_DISP_CLK,
+
+ /* DI0 data enable */
+ MX53_PAD_DI0_PIN15__DI0_PIN15,
+ /* DI0 HSYNC */
+ MX53_PAD_DI0_PIN2__DI0_PIN2,
+ /* DI0 VSYNC */
+ MX53_PAD_DI0_PIN3__DI0_PIN3,
+
+ MX53_PAD_DISP0_DAT0__DISP0_DAT0,
+ MX53_PAD_DISP0_DAT1__DISP0_DAT1,
+ MX53_PAD_DISP0_DAT2__DISP0_DAT2,
+ MX53_PAD_DISP0_DAT3__DISP0_DAT3,
+ MX53_PAD_DISP0_DAT4__DISP0_DAT4,
+ MX53_PAD_DISP0_DAT5__DISP0_DAT5,
+ MX53_PAD_DISP0_DAT6__DISP0_DAT6,
+ MX53_PAD_DISP0_DAT7__DISP0_DAT7,
+ MX53_PAD_DISP0_DAT8__DISP0_DAT8,
+ MX53_PAD_DISP0_DAT9__DISP0_DAT9,
+ MX53_PAD_DISP0_DAT10__DISP0_DAT10,
+ MX53_PAD_DISP0_DAT11__DISP0_DAT11,
+ MX53_PAD_DISP0_DAT12__DISP0_DAT12,
+ MX53_PAD_DISP0_DAT13__DISP0_DAT13,
+ MX53_PAD_DISP0_DAT14__DISP0_DAT14,
+ MX53_PAD_DISP0_DAT15__DISP0_DAT15,
+ MX53_PAD_DISP0_DAT16__DISP0_DAT16,
+ MX53_PAD_DISP0_DAT17__DISP0_DAT17,
+ MX53_PAD_DISP0_DAT18__DISP0_DAT18,
+ MX53_PAD_DISP0_DAT19__DISP0_DAT19,
+ MX53_PAD_DISP0_DAT20__DISP0_DAT20,
+ MX53_PAD_DISP0_DAT21__DISP0_DAT21,
+ MX53_PAD_DISP0_DAT22__DISP0_DAT22,
+ MX53_PAD_DISP0_DAT23__DISP0_DAT23,
+
+ MX53_PAD_LVDS0_TX3_P__LVDS0_TX3,
+ MX53_PAD_LVDS0_CLK_P__LVDS0_CLK,
+ MX53_PAD_LVDS0_TX2_P__LVDS0_TX2,
+ MX53_PAD_LVDS0_TX1_P__LVDS0_TX1,
+ MX53_PAD_LVDS0_TX0_P__LVDS0_TX0,
+
+ MX53_PAD_LVDS1_TX3_P__LVDS1_TX3,
+ MX53_PAD_LVDS1_CLK_P__LVDS1_CLK,
+ MX53_PAD_LVDS1_TX2_P__LVDS1_TX2,
+ MX53_PAD_LVDS1_TX1_P__LVDS1_TX1,
+ MX53_PAD_LVDS1_TX0_P__LVDS1_TX0,
+
+ /* audio and CSI clock out */
+ MX53_PAD_GPIO_0__SSI_EXT1_CLK,
+
+ MX53_PAD_CSI0_D12__CSI0_D12,
+ MX53_PAD_CSI0_D13__CSI0_D13,
+ MX53_PAD_CSI0_D14__CSI0_D14,
+ MX53_PAD_CSI0_D15__CSI0_D15,
+ MX53_PAD_CSI0_D16__CSI0_D16,
+ MX53_PAD_CSI0_D17__CSI0_D17,
+ MX53_PAD_CSI0_D18__CSI0_D18,
+ MX53_PAD_CSI0_D19__CSI0_D19,
+
+ MX53_PAD_CSI0_VSYNC__CSI0_VSYNC,
+ MX53_PAD_CSI0_MCLK__CSI0_HSYNC,
+ MX53_PAD_CSI0_PIXCLK__CSI0_PIXCLK,
+ /* Camera low power */
+ MX53_PAD_CSI0_D5__GPIO_5_23,
+
+ /* esdhc1 */
+ MX53_PAD_SD1_CMD__SD1_CMD,
+ MX53_PAD_SD1_CLK__SD1_CLK,
+ MX53_PAD_SD1_DATA0__SD1_DATA0,
+ MX53_PAD_SD1_DATA1__SD1_DATA1,
+ MX53_PAD_SD1_DATA2__SD1_DATA2,
+ MX53_PAD_SD1_DATA3__SD1_DATA3,
+
+ /* esdhc3 */
+ MX53_PAD_ATA_DATA8__SD3_DAT0,
+ MX53_PAD_ATA_DATA9__SD3_DAT1,
+ MX53_PAD_ATA_DATA10__SD3_DAT2,
+ MX53_PAD_ATA_DATA11__SD3_DAT3,
+ MX53_PAD_ATA_DATA0__SD3_DAT4,
+ MX53_PAD_ATA_DATA1__SD3_DAT5,
+ MX53_PAD_ATA_DATA2__SD3_DAT6,
+ MX53_PAD_ATA_DATA3__SD3_DAT7,
+ MX53_PAD_ATA_RESET_B__SD3_CMD,
+ MX53_PAD_ATA_IORDY__SD3_CLK,
+
+ /* FEC pins */
+ MX53_PAD_FEC_MDIO__FEC_MDIO,
+ MX53_PAD_FEC_REF_CLK__FEC_REF_CLK,
+ MX53_PAD_FEC_RX_ER__FEC_RX_ER,
+ MX53_PAD_FEC_CRS_DV__FEC_CRS_DV,
+ MX53_PAD_FEC_RXD1__FEC_RXD1,
+ MX53_PAD_FEC_RXD0__FEC_RXD0,
+ MX53_PAD_FEC_TX_EN__FEC_TX_EN,
+ MX53_PAD_FEC_TXD1__FEC_TXD1,
+ MX53_PAD_FEC_TXD0__FEC_TXD0,
+ MX53_PAD_FEC_MDC__FEC_MDC,
+
+ MX53_PAD_CSI0_D8__I2C1_SDA,
+ MX53_PAD_CSI0_D9__I2C1_SCL,
+
+ MX53_PAD_KEY_COL3__I2C2_SCL,
+ MX53_PAD_KEY_ROW3__I2C2_SDA,
+};
+
+static struct pad_desc mx53evk_pads[] = {
+ /* USB OTG USB_OC */
+ MX53_PAD_EIM_A24__GPIO_5_4,
+
+ /* USB OTG USB_PWR */
+ MX53_PAD_EIM_A23__GPIO_6_6,
+
+ /* DISPB0_SER_CLK */
+ MX53_PAD_EIM_D21__DISPB0_SER_CLK,
+
+ /* DI0_PIN1 */
+ MX53_PAD_EIM_D22__DISPB0_SER_DIN,
+
+ /* DVI I2C ENABLE */
+ MX53_PAD_EIM_D28__GPIO_3_28,
+
+ /* DVI DET */
+ MX53_PAD_EIM_D31__GPIO_3_31,
+
+ /* SDHC1 SD_CD */
+ MX53_PAD_EIM_DA13__GPIO_3_13,
+
+ /* SDHC1 SD_WP */
+ MX53_PAD_EIM_DA14__GPIO_3_14,
+
+ /* SDHC3 SD_CD */
+ MX53_PAD_EIM_DA11__GPIO_3_11,
+
+ /* SDHC3 SD_WP */
+ MX53_PAD_EIM_DA12__GPIO_3_12,
+
+ /* PWM backlight */
+ MX53_PAD_GPIO_1__PWMO,
+
+ /* USB HOST USB_PWR */
+ MX53_PAD_ATA_DA_2__GPIO_7_8,
+
+ /* USB HOST USB_RST */
+ MX53_PAD_CSI0_DATA_EN__GPIO_5_20,
+
+ /* USB HOST CARD_ON */
+ MX53_PAD_EIM_DA15__GPIO_3_15,
+
+ /* USB HOST CARD_RST */
+ MX53_PAD_ATA_DATA7__GPIO_2_7,
+
+ /* USB HOST WAN_WAKE */
+ MX53_PAD_EIM_D25__GPIO_3_25,
+
+ /* FEC_RST */
+ MX53_PAD_ATA_DA_0__GPIO_7_6,
+};
+
+static struct pad_desc mx53arm2_pads[] = {
+ /* USB OTG USB_OC */
+ MX53_PAD_EIM_D21__GPIO_3_21,
+
+ /* USB OTG USB_PWR */
+ MX53_PAD_EIM_D22__GPIO_3_22,
+
+ /* SDHC1 SD_CD */
+ MX53_PAD_GPIO_1__GPIO_1_1,
+
+ /* gpio backlight */
+ MX53_PAD_DI0_PIN4__GPIO_4_20,
+};
+
+static struct pad_desc mx53_nand_pads[] = {
+ MX53_PAD_NANDF_CLE__NANDF_CLE,
+ MX53_PAD_NANDF_ALE__NANDF_ALE,
+ MX53_PAD_NANDF_WP_B__NANDF_WP_B,
+ MX53_PAD_NANDF_WE_B__NANDF_WE_B,
+ MX53_PAD_NANDF_RE_B__NANDF_RE_B,
+ MX53_PAD_NANDF_RB0__NANDF_RB0,
+ MX53_PAD_NANDF_CS0__NANDF_CS0,
+ MX53_PAD_NANDF_CS1__NANDF_CS1 ,
+ MX53_PAD_NANDF_CS2__NANDF_CS2,
+ MX53_PAD_NANDF_CS3__NANDF_CS3 ,
+ MX53_PAD_EIM_DA0__EIM_DA0,
+ MX53_PAD_EIM_DA1__EIM_DA1,
+ MX53_PAD_EIM_DA2__EIM_DA2,
+ MX53_PAD_EIM_DA3__EIM_DA3,
+ MX53_PAD_EIM_DA4__EIM_DA4,
+ MX53_PAD_EIM_DA5__EIM_DA5,
+ MX53_PAD_EIM_DA6__EIM_DA6,
+ MX53_PAD_EIM_DA7__EIM_DA7,
+};
+
/* working point(wp): 0 - 800MHz; 1 - 166.25MHz; */
static struct cpu_wp cpu_wp_auto[] = {
{
@@ -84,7 +408,7 @@ static struct cpu_wp cpu_wp_auto[] = {
.mfd = 11,
.mfn = 5,
.cpu_podf = 0,
- .cpu_voltage = 1175000,},
+ .cpu_voltage = 1150000,},
{
.pll_rate = 800000000,
.cpu_rate = 800000000,
@@ -93,10 +417,10 @@ static struct cpu_wp cpu_wp_auto[] = {
.mfd = 2,
.mfn = 1,
.cpu_podf = 0,
- .cpu_voltage = 1100000,},
+ .cpu_voltage = 1050000,},
{
.pll_rate = 800000000,
- .cpu_rate = 166250000,
+ .cpu_rate = 160000000,
.pdf = 4,
.mfi = 8,
.mfd = 2,
@@ -107,7 +431,24 @@ static struct cpu_wp cpu_wp_auto[] = {
static struct fb_videomode video_modes[] = {
{
- /* 720p60 TV output */
+ /* NTSC TV output */
+ "TV-NTSC", 60, 720, 480, 74074,
+ 122, 15,
+ 18, 26,
+ 1, 1,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | FB_SYNC_EXT,
+ FB_VMODE_INTERLACED,
+ 0,},
+ {
+ /* PAL TV output */
+ "TV-PAL", 50, 720, 576, 74074,
+ 132, 11,
+ 22, 26,
+ 1, 1,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | FB_SYNC_EXT,
+ FB_VMODE_INTERLACED | FB_VMODE_ODD_FLD_FIRST,
+ 0,},
+ {
"720P60", 60, 1280, 720, 13468,
260, 109,
25, 4,
@@ -117,12 +458,35 @@ static struct fb_videomode video_modes[] = {
FB_VMODE_NONINTERLACED,
0,},
{
- /* MITSUBISHI LVDS panel */
+ /* 800x480 @ 57 Hz , pixel clk @ 27MHz */
+ "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10,
+ FB_SYNC_CLK_LAT_FALL,
+ FB_VMODE_NONINTERLACED,
+ 0,},
+ {
+ /* 1600x1200 @ 60 Hz 162M pixel clk*/
+ "UXGA", 60, 1600, 1200, 6172,
+ 304, 64,
+ 1, 46,
+ 192, 3,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT |
+ FB_SYNC_EXT,
+ FB_VMODE_NONINTERLACED,
+ 0,},
+ {
+ "1080P60", 60, 1920, 1080, 7692,
+ 100, 40,
+ 30, 3,
+ 10, 2,
+ FB_SYNC_EXT,
+ FB_VMODE_NONINTERLACED,
+ 0,},
+ {
"XGA", 60, 1024, 768, 15385,
220, 40,
21, 7,
60, 10,
- 0,
+ FB_SYNC_EXT,
FB_VMODE_NONINTERLACED,
0,},
};
@@ -147,9 +511,76 @@ static struct platform_pwm_backlight_data mxc_pwm_backlight_data = {
.pwm_id = 1,
.max_brightness = 255,
.dft_brightness = 128,
- .pwm_period_ns = 78770,
+ .pwm_period_ns = 50000,
};
+static void flexcan_xcvr_enable(int id, int en)
+{
+ static int pwdn;
+ if (id < 0 || id > 1)
+ return;
+
+ if (en) {
+ if (!(pwdn++))
+ gpio_set_value(MX53_12V_EN, 1);
+
+ if (id == 0) {
+ gpio_set_value(MX53_CAN1_EN1, 1);
+ gpio_set_value(MX53_CAN1_EN2, 1);
+ } else {
+ gpio_set_value(MX53_CAN2_EN1, 1);
+ gpio_set_value(MX53_CAN2_EN2, 1);
+ }
+
+ } else {
+ if (!(--pwdn))
+ gpio_set_value(MX53_12V_EN, 0);
+
+ if (id == 0) {
+ gpio_set_value(MX53_CAN1_EN1, 0);
+ gpio_set_value(MX53_CAN1_EN2, 0);
+ } else {
+ gpio_set_value(MX53_CAN2_EN1, 0);
+ gpio_set_value(MX53_CAN2_EN2, 0);
+ }
+ }
+}
+
+static struct flexcan_platform_data flexcan0_data = {
+ .core_reg = NULL,
+ .io_reg = NULL,
+ .xcvr_enable = flexcan_xcvr_enable,
+ .br_clksrc = 1,
+ .br_rjw = 2,
+ .br_presdiv = 5,
+ .br_propseg = 5,
+ .br_pseg1 = 4,
+ .br_pseg2 = 7,
+ .bcc = 1,
+ .srx_dis = 1,
+ .smp = 1,
+ .boff_rec = 1,
+ .ext_msg = 1,
+ .std_msg = 1,
+};
+static struct flexcan_platform_data flexcan1_data = {
+ .core_reg = NULL,
+ .io_reg = NULL,
+ .xcvr_enable = flexcan_xcvr_enable,
+ .br_clksrc = 1,
+ .br_rjw = 2,
+ .br_presdiv = 5,
+ .br_propseg = 5,
+ .br_pseg1 = 4,
+ .br_pseg2 = 7,
+ .bcc = 1,
+ .srx_dis = 1,
+ .boff_rec = 1,
+ .ext_msg = 1,
+ .std_msg = 1,
+};
+
+
extern void mx5_ipu_reset(void);
static struct mxc_ipu_config mxc_ipu_data = {
.rev = 3,
@@ -161,10 +592,74 @@ static struct mxc_vpu_platform_data mxc_vpu_data = {
.reset = mx5_vpu_reset,
};
-extern void mx53_evk_gpio_spi_chipselect_active(int cspi_mode, int status,
- int chipselect);
-extern void mx53_evk_gpio_spi_chipselect_inactive(int cspi_mode, int status,
- int chipselect);
+static struct fec_platform_data fec_data = {
+ .phy = PHY_INTERFACE_MODE_RMII,
+ .phy_mask = ~1UL,
+};
+
+/* workaround for ecspi chipselect pin may not keep correct level when idle */
+static void mx53_evk_gpio_spi_chipselect_active(int cspi_mode, int status,
+ int chipselect)
+{
+ switch (cspi_mode) {
+ case 1:
+ switch (chipselect) {
+ case 0x1:
+ {
+ struct pad_desc eim_d19_gpio = MX53_PAD_EIM_D19__GPIO_3_19;
+ struct pad_desc cspi_ss0 = MX53_PAD_EIM_EB2__CSPI_SS0;
+
+ /* de-select SS1 of instance: ecspi1. */
+ mxc_iomux_v3_setup_pad(&eim_d19_gpio);
+ mxc_iomux_v3_setup_pad(&cspi_ss0);
+ }
+ break;
+ case 0x2:
+ {
+ struct pad_desc eim_eb2_gpio = MX53_PAD_EIM_EB2__GPIO_2_30;
+ struct pad_desc cspi_ss1 = MX53_PAD_EIM_D19__CSPI_SS1;
+
+ /* de-select SS0 of instance: ecspi1. */
+ mxc_iomux_v3_setup_pad(&eim_eb2_gpio);
+ mxc_iomux_v3_setup_pad(&cspi_ss1);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2:
+ break;
+ case 3:
+ break;
+ default:
+ break;
+ }
+}
+
+static void mx53_evk_gpio_spi_chipselect_inactive(int cspi_mode, int status,
+ int chipselect)
+{
+ switch (cspi_mode) {
+ case 1:
+ switch (chipselect) {
+ case 0x1:
+ break;
+ case 0x2:
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2:
+ break;
+ case 3:
+ break;
+ default:
+ break;
+ }
+}
+
static struct mxc_spi_master mxcspi1_data = {
.maxchipselect = 4,
.spi_version = 23,
@@ -180,10 +675,143 @@ static struct mxc_srtc_platform_data srtc_data = {
.srtc_sec_mode_addr = 0x83F98840,
};
+static struct mxc_dvfs_platform_data dvfs_core_data = {
+ .reg_id = "SW1",
+ .clk1_id = "cpu_clk",
+ .clk2_id = "gpc_dvfs_clk",
+ .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET,
+ .gpc_vcr_offset = MXC_GPC_VCR_OFFSET,
+ .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET,
+ .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET,
+ .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET,
+ .prediv_mask = 0x1F800,
+ .prediv_offset = 11,
+ .prediv_val = 3,
+ .div3ck_mask = 0xE0000000,
+ .div3ck_offset = 29,
+ .div3ck_val = 2,
+ .emac_val = 0x08,
+ .upthr_val = 25,
+ .dnthr_val = 9,
+ .pncthr_val = 33,
+ .upcnt_val = 10,
+ .dncnt_val = 10,
+ .delay_time = 30,
+ .num_wp = 3,
+};
+
static struct tve_platform_data tve_data = {
.dac_reg = "VVIDEO",
};
+static struct ldb_platform_data ldb_data = {
+ .lvds_bg_reg = "VAUDIO",
+ .ext_ref = 1,
+};
+
+static struct pad_desc mx53esai_pads[] = {
+ MX53_PAD_FEC_MDIO__ESAI_SCKR,
+ MX53_PAD_FEC_REF_CLK__ESAI_FSR,
+ MX53_PAD_FEC_RX_ER__ESAI_HCKR,
+ MX53_PAD_FEC_CRS_DV__ESAI_SCKT,
+ MX53_PAD_FEC_RXD1__ESAI_FST,
+ MX53_PAD_FEC_RXD0__ESAI_HCKT,
+ MX53_PAD_FEC_TX_EN__ESAI_TX3_RX2,
+ MX53_PAD_FEC_TXD1__ESAI_TX2_RX3,
+ MX53_PAD_FEC_TXD0__ESAI_TX4_RX1,
+ MX53_PAD_FEC_MDC__ESAI_TX5_RX0,
+ MX53_PAD_NANDF_CS2__ESAI_TX0,
+ MX53_PAD_NANDF_CS3__ESAI_TX1,
+};
+
+void gpio_activate_esai_ports(void)
+{
+ mxc_iomux_v3_setup_multiple_pads(mx53esai_pads,
+ ARRAY_SIZE(mx53esai_pads));
+}
+
+static struct mxc_esai_platform_data esai_data = {
+ .activate_esai_ports = gpio_activate_esai_ports,
+};
+
+void gpio_cs42888_pdwn(int pdwn)
+{
+ if (pdwn)
+ gpio_set_value(MX53_ESAI_RESET, 0);
+ else
+ gpio_set_value(MX53_ESAI_RESET, 1);
+}
+EXPORT_SYMBOL(gpio_cs42888_pdwn);
+
+static void gpio_usbotg_vbus_active(void)
+{
+ if (board_is_mx53_arm2()) {
+ /* MX53 ARM2 CPU board */
+ /* Enable OTG VBus with GPIO low */
+ gpio_set_value(ARM2_OTG_VBUS, 0);
+ } else if (board_is_mx53_evk_a()) {
+ /* MX53 EVK board ver A*/
+ /* Enable OTG VBus with GPIO low */
+ gpio_set_value(EVK_OTG_VBUS, 0);
+ } else if (board_is_mx53_evk_b()) {
+ /* MX53 EVK board ver B*/
+ /* Enable OTG VBus with GPIO high */
+ gpio_set_value(EVK_OTG_VBUS, 1);
+ }
+}
+
+static void gpio_usbotg_vbus_inactive(void)
+{
+ if (board_is_mx53_arm2()) {
+ /* MX53 ARM2 CPU board */
+ /* Disable OTG VBus with GPIO high */
+ gpio_set_value(ARM2_OTG_VBUS, 1);
+ } else if (board_is_mx53_evk_a()) {
+ /* MX53 EVK board ver A*/
+ /* Disable OTG VBus with GPIO high */
+ gpio_set_value(EVK_OTG_VBUS, 1);
+ } else if (board_is_mx53_evk_b()) {
+ /* MX53 EVK board ver B*/
+ /* Disable OTG VBus with GPIO low */
+ gpio_set_value(EVK_OTG_VBUS, 0);
+ }
+}
+
+static void mx53_gpio_usbotg_driver_vbus(bool on)
+{
+ if (on)
+ gpio_usbotg_vbus_active();
+ else
+ gpio_usbotg_vbus_inactive();
+}
+
+static void mx53_gpio_host1_driver_vbus(bool on)
+{
+ if (on)
+ gpio_set_value(EVK_USBH1_VBUS, 1);
+ else
+ gpio_set_value(EVK_USBH1_VBUS, 0);
+}
+
+static void adv7180_pwdn(int pwdn)
+{
+ gpio_request(MX53_TVIN_PWR, "tvin-pwr");
+ gpio_direction_output(MX53_TVIN_PWR, 0);
+ if (pwdn)
+ gpio_set_value(MX53_TVIN_PWR, 0);
+ else
+ gpio_set_value(MX53_TVIN_PWR, 1);
+}
+
+static struct mxc_tvin_platform_data adv7180_data = {
+ .dvddio_reg = NULL,
+ .dvdd_reg = NULL,
+ .avdd_reg = NULL,
+ .pvdd_reg = NULL,
+ .pwdn = adv7180_pwdn,
+ .reset = NULL,
+};
+
static struct resource mxcfb_resources[] = {
[0] = {
.flags = IORESOURCE_MEM,
@@ -193,101 +821,43 @@ static struct resource mxcfb_resources[] = {
static struct mxc_fb_platform_data fb_data[] = {
{
.interface_pix_fmt = IPU_PIX_FMT_RGB565,
- .mode_str = "800x480M-16@55",
+ .mode_str = "CLAA-WVGA",
+ .mode = video_modes,
+ .num_modes = ARRAY_SIZE(video_modes),
},
{
- .interface_pix_fmt = IPU_PIX_FMT_RGB24,
+ .interface_pix_fmt = IPU_PIX_FMT_BGR24,
.mode_str = "1024x768M-16@60",
+ .mode = video_modes,
+ .num_modes = ARRAY_SIZE(video_modes),
},
};
-static int __initdata enable_vga = { 0 };
-static int __initdata enable_tv = { 0 };
-static int __initdata enable_dvi = { 0 };
-
-static void wvga_reset(void)
-{
-}
-
-static struct mxc_lcd_platform_data lcd_wvga_data = {
- .reset = wvga_reset,
-};
-
-static struct platform_device lcd_wvga_device = {
- .name = "lcd_claa",
-};
-
+extern int primary_di;
static int __init mxc_init_fb(void)
{
if (!machine_is_mx53_evk())
return 0;
- /* by default, fb0 is wvga, fb1 is vga or tv */
- if (enable_vga) {
- printk(KERN_INFO "VGA monitor is primary\n");
- } else if (enable_tv == 2)
- printk(KERN_INFO "HDTV is primary\n");
- else if (enable_dvi)
- printk(KERN_INFO "DVI is primary\n");
- else
- printk(KERN_INFO "WVGA LCD panel is primary\n");
-
- if (enable_tv) {
- printk(KERN_INFO "HDTV is specified as %d\n", enable_tv);
- fb_data[1].interface_pix_fmt = IPU_PIX_FMT_YUV444;
- fb_data[1].mode = &(video_modes[0]);
- }
-
- if (enable_dvi) {
- fb_data[0].mode_str = "1024x768M-16@60";
- fb_data[0].interface_pix_fmt = IPU_PIX_FMT_RGB24;
- }
-
- /* Once a customer knows the platform configuration,
- this should be simplified to what is desired.
- */
- if (enable_vga || enable_tv == 2) {
- /*
- * DI1 -> DP-BG channel:
- *
- * dev di-out-fmt default-videmode
- *
- * 1. VGA RGB 1024x768M-16@60
- * 2. TVE YUV video_modes[0]
- */
+ if (primary_di) {
+ printk(KERN_INFO "DI1 is primary\n");
+ /* DI1 -> DP-BG channel: */
mxc_fb_devices[1].num_resources = ARRAY_SIZE(mxcfb_resources);
mxc_fb_devices[1].resource = mxcfb_resources;
mxc_register_device(&mxc_fb_devices[1], &fb_data[1]);
- if (fb_data[0].mode_str || fb_data[0].mode)
- /*
- * DI0 -> DC channel:
- *
- * dev di-out-fmt default-videmode
- *
- * 1. WVGA RGB 800x480M-16@55
- */
- mxc_register_device(&mxc_fb_devices[0], &fb_data[0]);
+
+ /* DI0 -> DC channel: */
+ mxc_register_device(&mxc_fb_devices[0], &fb_data[0]);
} else {
- /*
- * DI0 -> DP-BG channel:
- *
- * dev di-out-fmt default-videmode
- *
- * 1. WVGA RGB 800x480M-16@55
- */
+ printk(KERN_INFO "DI0 is primary\n");
+
+ /* DI0 -> DP-BG channel: */
mxc_fb_devices[0].num_resources = ARRAY_SIZE(mxcfb_resources);
mxc_fb_devices[0].resource = mxcfb_resources;
mxc_register_device(&mxc_fb_devices[0], &fb_data[0]);
- if (fb_data[1].mode_str || fb_data[1].mode)
- /*
- * DI1 -> DC channel:
- *
- * dev di-out-fmt default-videmode
- *
- * 1. VGA RGB 1024x768M-16@60
- * 2. TVE YUV video_modes[0]
- */
- mxc_register_device(&mxc_fb_devices[1], &fb_data[1]);
+
+ /* DI1 -> DC channel: */
+ mxc_register_device(&mxc_fb_devices[1], &fb_data[1]);
}
/*
@@ -299,33 +869,19 @@ static int __init mxc_init_fb(void)
}
device_initcall(mxc_init_fb);
-static int __init dvi_setup(char *s)
-{
- enable_dvi = 1;
- return 1;
-}
-__setup("dvi", dvi_setup);
-
-static int __init vga_setup(char *__unused)
-{
- enable_vga = 1;
- return 1;
-}
-__setup("vga", vga_setup);
-
-static int __init tv_setup(char *s)
+static void camera_pwdn(int pwdn)
{
- enable_tv = 1;
- if (strcmp(s, "2") == 0 || strcmp(s, "=2") == 0)
- enable_tv = 2;
- return 1;
+ gpio_request(MX53_TVIN_PWR, "tvin-pwr");
+ gpio_direction_output(MX53_TVIN_PWR, 0);
+ gpio_set_value(MX53_TVIN_PWR, pwdn);
}
-__setup("hdtv", tv_setup);
static struct mxc_camera_platform_data camera_data = {
.analog_regulator = "VSD",
+ .gpo_regulator = "VVIDEO",
.mclk = 24000000,
.csi = 0,
+ .pwdn = camera_pwdn,
};
static struct i2c_board_info mxc_i2c0_board_info[] __initdata = {
@@ -334,6 +890,27 @@ static struct i2c_board_info mxc_i2c0_board_info[] __initdata = {
.addr = 0x3C,
.platform_data = (void *)&camera_data,
},
+ {
+ .type = "adv7180",
+ .addr = 0x21,
+ .platform_data = (void *)&adv7180_data,
+ },
+ {
+ .type = "cs42888",
+ .addr = 0x48,
+ },
+};
+
+static void sii9022_hdmi_reset(void)
+{
+ gpio_set_value(MX53_DVI_RESET, 0);
+ msleep(10);
+ gpio_set_value(MX53_DVI_RESET, 1);
+ msleep(10);
+}
+
+static struct mxc_lcd_platform_data sii9022_hdmi_data = {
+ .reset = sii9022_hdmi_reset,
};
/* TO DO add platform data */
@@ -345,7 +922,7 @@ static struct i2c_board_info mxc_i2c1_board_info[] __initdata = {
{
.type = "tsc2007",
.addr = 0x48,
- .irq = IOMUX_TO_IRQ(MX53_PIN_EIM_A25),
+ .irq = IOMUX_TO_IRQ_V3(EVK_TS_INT),
},
{
.type = "backlight-i2c",
@@ -359,6 +936,40 @@ static struct i2c_board_info mxc_i2c1_board_info[] __initdata = {
.type = "eeprom",
.addr = 0x50,
},
+ {
+ .type = "sii9022",
+ .addr = 0x39,
+ .platform_data = &sii9022_hdmi_data,
+ },
+};
+
+static struct mtd_partition mxc_dataflash_partitions[] = {
+ {
+ .name = "bootloader",
+ .offset = 0,
+ .size = 0x000100000,},
+ {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,},
+};
+
+static struct flash_platform_data mxc_spi_flash_data[] = {
+ {
+ .name = "mxc_dataflash",
+ .parts = mxc_dataflash_partitions,
+ .nr_parts = ARRAY_SIZE(mxc_dataflash_partitions),
+ .type = "at45db321d",}
+};
+
+
+static struct spi_board_info mxc_dataflash_device[] __initdata = {
+ {
+ .modalias = "mxc_dataflash",
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 1,
+ .platform_data = &mxc_spi_flash_data[0],},
};
static int sdhc_write_protect(struct device *dev)
@@ -367,9 +978,9 @@ static int sdhc_write_protect(struct device *dev)
if (!board_is_mx53_arm2()) {
if (to_platform_device(dev)->id == 0)
- rc = gpio_get_value(IOMUX_TO_GPIO(MX53_PIN_EIM_DA14));
+ rc = gpio_get_value(EVK_SD1_WP);
else
- rc = gpio_get_value(IOMUX_TO_GPIO(MX53_PIN_EIM_DA12));
+ rc = gpio_get_value(EVK_SD3_WP);
}
return rc;
@@ -380,14 +991,14 @@ static unsigned int sdhc_get_card_det_status(struct device *dev)
int ret;
if (board_is_mx53_arm2()) {
if (to_platform_device(dev)->id == 0)
- ret = gpio_get_value(IOMUX_TO_GPIO(MX53_PIN_GPIO_1));
+ ret = gpio_get_value(ARM2_SD1_CD);
else
ret = 1;
} else {
if (to_platform_device(dev)->id == 0) {
- ret = gpio_get_value(IOMUX_TO_GPIO(MX53_PIN_EIM_DA13));
+ ret = gpio_get_value(EVK_SD1_CD);
} else{ /* config the det pin for SDHC3 */
- ret = gpio_get_value(IOMUX_TO_GPIO(MX53_PIN_EIM_DA11));
+ ret = gpio_get_value(EVK_SD3_CD);
}
}
@@ -410,13 +1021,170 @@ static struct mxc_mmc_platform_data mmc1_data = {
static struct mxc_mmc_platform_data mmc3_data = {
.ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30
| MMC_VDD_31_32,
- .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA
+ | MMC_CAP_DATA_DDR,
.min_clk = 400000,
.max_clk = 50000000,
.card_inserted_state = 0,
.status = sdhc_get_card_det_status,
.wp_status = sdhc_write_protect,
.clock_mmc = "esdhc_clk",
+ .clk_always_on = 1,
+};
+
+/* return value 1 failure, 0 success */
+static int write_phy_ctl_ack_polling(u32 data, void __iomem *mmio,
+ int max_iterations, u32 exp_val)
+{
+ enum {
+ PORT_PHY_CTL = 0x178, /* Port0 PHY Control */
+ PORT_PHY_SR = 0x17c, /* Port0 PHY Status */
+ /* PORT_PHY_SR */
+ PORT_PHY_STAT_DATA_LOC = 0,
+ PORT_PHY_STAT_ACK_LOC = 18,
+ };
+ int i;
+ u32 val;
+
+ writel(data, mmio + PORT_PHY_CTL);
+
+ for (i = 0; i < max_iterations + 1; i++) {
+ val = readl(mmio + PORT_PHY_SR);
+ val = (val >> PORT_PHY_STAT_ACK_LOC) & 0x1;
+ if (val == exp_val)
+ return 0;
+ if (i == max_iterations) {
+ printk(KERN_ERR "Wait for CR ACK error!\n");
+ return 1;
+ }
+ msleep(1);
+ }
+ return 0;
+}
+
+/* HW Initialization, if return 1, initialization is failed. */
+static int sata_init(struct device *dev)
+{
+ enum {
+ HOST_CAP = 0x00,
+ HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
+ HOST_PORTS_IMPL = 0x0c,
+ HOST_TIMER1MS = 0xe0, /* Timer 1-ms */
+ /* Offest used to control the MPLL input clk */
+ PHY_CR_CLOCK_FREQ_OVRD = 0x12,
+
+ PORT_PHY_CTL = 0x178, /* Port0 PHY Control */
+ /* PORT_PHY_CTL bits */
+ PORT_PHY_CTL_CAP_ADR_LOC = 0x10000,
+ PORT_PHY_CTL_CAP_DAT_LOC = 0x20000,
+ PORT_PHY_CTL_WRITE_LOC = 0x40000,
+ };
+ void __iomem *mmio;
+ struct clk *clk;
+ int rc = 0;
+ u32 tmpdata;
+
+ clk = clk_get(dev, "sata_clk");
+ clk_enable(clk);
+
+ mmio = ioremap(MX53_SATA_BASE_ADDR, SZ_4K);
+
+ tmpdata = readl(mmio + HOST_CAP);
+ if (!(tmpdata & HOST_CAP_SSS)) {
+ tmpdata |= HOST_CAP_SSS;
+ writel(tmpdata, mmio + HOST_CAP);
+ }
+
+ if (!(readl(mmio + HOST_PORTS_IMPL) & 0x1))
+ writel((readl(mmio + HOST_PORTS_IMPL) | 0x1),
+ mmio + HOST_PORTS_IMPL);
+
+ /* Get the AHB clock rate, and configure the TIMER1MS reg */
+ clk = clk_get(NULL, "ahb_clk");
+ tmpdata = clk_get_rate(clk) / 1000;
+ writel(tmpdata, mmio + HOST_TIMER1MS);
+
+ /* write addr */
+ tmpdata = PHY_CR_CLOCK_FREQ_OVRD;
+ writel(tmpdata, mmio + PORT_PHY_CTL);
+ /* capture addr */
+ tmpdata |= PORT_PHY_CTL_CAP_ADR_LOC;
+ /* Wait for ack */
+ if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 1)) {
+ rc = 1;
+ goto err0;
+ }
+
+ /* deassert cap data */
+ tmpdata &= 0xFFFF;
+ /* wait for ack de-assertion */
+ if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 0)) {
+ rc = 1;
+ goto err0;
+ }
+
+ /* write data */
+ /* Configure the PHY CLK input refer to different OSC
+ * For 25MHz, pre[13,14]:01, ncy[12,8]:06,
+ * ncy5[7,6]:02, int_ctl[5,3]:0, prop_ctl[2,0]:7.
+ * For 50MHz, pre:00, ncy:06, ncy5:02, int_ctl:0, prop_ctl:7.
+ */
+ /* EVK revA */
+ if (board_is_mx53_evk_a())
+ tmpdata = (0x1 << 15) | (0x1 << 13) | (0x6 << 8)
+ | (0x2 << 6) | 0x7;
+ /* EVK revB */
+ else if (board_is_mx53_evk_b())
+ tmpdata = (0x1 << 15) | (0x0 << 13) | (0x6 << 8)
+ | (0x2 << 6) | 0x7;
+
+ writel(tmpdata, mmio + PORT_PHY_CTL);
+ /* capture data */
+ tmpdata |= PORT_PHY_CTL_CAP_DAT_LOC;
+ /* wait for ack */
+ if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 1)) {
+ rc = 1;
+ goto err0;
+ }
+
+ /* deassert cap data */
+ tmpdata &= 0xFFFF;
+ /* wait for ack de-assertion */
+ if (write_phy_ctl_ack_polling(tmpdata, mmio, 100, 0)) {
+ rc = 1;
+ goto err0;
+ }
+
+ /* assert wr signal and wait for ack */
+ if (write_phy_ctl_ack_polling(PORT_PHY_CTL_WRITE_LOC, mmio, 100, 1)) {
+ rc = 1;
+ goto err0;
+ }
+ /* deassert rd _signal and wait for ack de-assertion */
+ if (write_phy_ctl_ack_polling(0, mmio, 100, 0)) {
+ rc = 1;
+ goto err0;
+ }
+
+ msleep(10);
+
+err0:
+ iounmap(mmio);
+ return rc;
+}
+
+static void sata_exit(struct device *dev)
+{
+ struct clk *clk;
+
+ clk = clk_get(dev, "sata_clk");
+ clk_disable(clk);
+ clk_put(clk);
+}
+
+static struct ahci_platform_data sata_data = {
+ .init = sata_init,
+ .exit = sata_exit,
};
static int mxc_sgtl5000_amp_enable(int enable)
@@ -427,7 +1195,7 @@ return 0;
static int headphone_det_status(void)
{
- return (gpio_get_value(IOMUX_TO_GPIO(MX53_PIN_ATA_DATA5)) == 0);
+ return (gpio_get_value(MX53_HP_DETECT) == 0);
}
static int mxc_sgtl5000_init(void);
@@ -436,7 +1204,7 @@ static struct mxc_audio_platform_data sgtl5000_data = {
.ssi_num = 1,
.src_port = 2,
.ext_port = 5,
- .hp_irq = IOMUX_TO_IRQ(MX53_PIN_ATA_DATA5),
+ .hp_irq = IOMUX_TO_IRQ(MX53_HP_DETECT),
.hp_status = headphone_det_status,
.amp_enable = mxc_sgtl5000_amp_enable,
.init = mxc_sgtl5000_init,
@@ -474,6 +1242,139 @@ static struct platform_device mxc_sgtl5000_device = {
.name = "imx-3stack-sgtl5000",
};
+static struct mxc_mlb_platform_data mlb_data = {
+ .reg_nvcc = "VCAM",
+ .mlb_clk = "mlb_clk",
+};
+
+/* NAND Flash Partitions */
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition nand_flash_partitions[] = {
+ {
+ .name = "BOOT",
+ .offset = 0,
+ .size = 7 * 1024 * 1024},
+ {
+ .name = "MISC",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 1 * 1024 * 1024},
+ {
+ .name = "RECOVERY",
+ .offset = MTDPART_OFS_APPEND,
+ .size = 20 * 1024 * 1024},
+ {
+ .name = "ROOT",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL},
+};
+#endif
+
+static int nand_init(void)
+{
+ u32 i, reg;
+ void __iomem *base;
+
+ #define M4IF_GENP_WEIM_MM_MASK 0x00000001
+ #define WEIM_GCR2_MUX16_BYP_GRANT_MASK 0x00001000
+
+ base = ioremap(MX53_BASE_ADDR(M4IF_BASE_ADDR), SZ_4K);
+ reg = __raw_readl(base + 0xc);
+ reg &= ~M4IF_GENP_WEIM_MM_MASK;
+ __raw_writel(reg, base + 0xc);
+
+ iounmap(base);
+
+ base = ioremap(MX53_BASE_ADDR(WEIM_BASE_ADDR), SZ_4K);
+ for (i = 0x4; i < 0x94; i += 0x18) {
+ reg = __raw_readl((u32)base + i);
+ reg &= ~WEIM_GCR2_MUX16_BYP_GRANT_MASK;
+ __raw_writel(reg, (u32)base + i);
+ }
+
+ iounmap(base);
+
+ return 0;
+}
+
+static struct flash_platform_data mxc_nand_data = {
+#ifdef CONFIG_MTD_PARTITIONS
+ .parts = nand_flash_partitions,
+ .nr_parts = ARRAY_SIZE(nand_flash_partitions),
+#endif
+ .width = 1,
+ .init = nand_init,
+};
+
+static struct mxc_spdif_platform_data mxc_spdif_data = {
+ .spdif_tx = 1,
+ .spdif_rx = 0,
+ .spdif_clk_44100 = 0, /* Souce from CKIH1 for 44.1K */
+ .spdif_clk_48000 = 7, /* Source from CKIH2 for 48k and 32k */
+ .spdif_clkid = 0,
+ .spdif_clk = NULL, /* spdif bus clk */
+};
+
+static struct mxc_audio_platform_data mxc_surround_audio_data = {
+ .ext_ram = 1,
+};
+
+
+static struct platform_device mxc_alsa_surround_device = {
+ .name = "imx-3stack-cs42888",
+};
+
+static int __initdata mxc_apc_on = { 0 }; /* OFF: 0 (default), ON: 1 */
+static int __init apc_setup(char *__unused)
+{
+ mxc_apc_on = 1;
+ printk(KERN_INFO "Automotive Port Card is Plugged on\n");
+ return 1;
+}
+__setup("apc", apc_setup);
+
+static int __initdata enable_w1 = { 0 };
+static int __init w1_setup(char *__unused)
+{
+ enable_w1 = 1;
+ return cpu_is_mx53();
+}
+__setup("w1", w1_setup);
+
+
+static int __initdata enable_spdif = { 0 };
+static int __init spdif_setup(char *__unused)
+{
+ enable_spdif = 1;
+ return 1;
+}
+__setup("spdif", spdif_setup);
+
+static struct android_pmem_platform_data android_pmem_pdata = {
+ .name = "pmem_adsp",
+ .start = 0,
+ .size = SZ_64M,
+ .no_allocator = 0,
+ .cached = PMEM_NONCACHE_NORMAL,
+};
+
+static struct android_pmem_platform_data android_pmem_gpu_pdata = {
+ .name = "pmem_gpu",
+ .start = 0,
+ .size = SZ_32M,
+ .no_allocator = 0,
+ .cached = PMEM_CACHE_ENABLE,
+};
+
+static struct android_usb_platform_data android_usb_pdata = {
+ .vendor_id = 0x0bb4,
+ .product_id = 0x0c01,
+ .adb_product_id = 0x0c02,
+ .version = 0x0100,
+ .product_name = "Android Phone",
+ .manufacturer_name = "Freescale",
+ .nluns = 3,
+};
+
/*!
* Board specific fixup function. It is called by \b setup_arch() in
* setup.c file very early on during kernel starts. It allows the user to
@@ -495,17 +1396,38 @@ static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags,
int gpu_mem = SZ_128M;
int fb_mem = SZ_32M;
char *str;
+ int size;
mxc_set_cpu_type(MXC_CPU_MX53);
get_cpu_wp = mx53_evk_get_cpu_wp;
set_num_cpu_wp = mx53_evk_set_num_cpu_wp;
+ for_each_tag(t, tags) {
+ if (t->hdr.tag != ATAG_MEM)
+ continue;
+ size = t->u.mem.size;
+
+ android_pmem_pdata.start =
+ PHYS_OFFSET + size - android_pmem_pdata.size;
+ android_pmem_gpu_pdata.start =
+ android_pmem_pdata.start - android_pmem_gpu_pdata.size;
+ gpu_device.resource[5].start =
+ android_pmem_gpu_pdata.start - SZ_16M;
+ gpu_device.resource[5].end =
+ gpu_device.resource[5].start + SZ_16M - 1;
+ size -= android_pmem_pdata.size;
+ size -= android_pmem_gpu_pdata.size;
+ size -= SZ_16M;
+ t->u.mem.size = size;
+ }
+#if 0
for_each_tag(mem_tag, tags) {
if (mem_tag->hdr.tag == ATAG_MEM) {
total_mem = mem_tag->u.mem.size;
left_mem = total_mem - gpu_mem - fb_mem;
break;
+
}
}
@@ -557,6 +1479,140 @@ static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags,
}
#endif
}
+#endif
+}
+
+static void __init mx53_evk_io_init(void)
+{
+ mxc_iomux_v3_setup_multiple_pads(mx53common_pads,
+ ARRAY_SIZE(mx53common_pads));
+
+ if (board_is_mx53_arm2()) {
+ /* MX53 ARM2 CPU board */
+ pr_info("MX53 ARM2 board \n");
+ mxc_iomux_v3_setup_multiple_pads(mx53arm2_pads,
+ ARRAY_SIZE(mx53arm2_pads));
+
+ /* Config GPIO for OTG VBus */
+ gpio_request(ARM2_OTG_VBUS, "otg-vbus");
+ gpio_direction_output(ARM2_OTG_VBUS, 1);
+
+ gpio_request(ARM2_SD1_CD, "sdhc1-cd");
+ gpio_direction_input(ARM2_SD1_CD); /* SD1 CD */
+
+ gpio_request(ARM2_LCD_CONTRAST, "lcd-contrast");
+ gpio_direction_output(ARM2_LCD_CONTRAST, 1);
+ } else {
+ /* MX53 EVK board */
+ pr_info("MX53 EVK board \n");
+ mxc_iomux_v3_setup_multiple_pads(mx53evk_pads,
+ ARRAY_SIZE(mx53evk_pads));
+
+ /* Host1 Vbus with GPIO high */
+ gpio_request(EVK_USBH1_VBUS, "usbh1-vbus");
+ gpio_direction_output(EVK_USBH1_VBUS, 1);
+ /* shutdown the Host1 Vbus when system bring up,
+ * Vbus will be opened in Host1 driver's probe function */
+ gpio_set_value(EVK_USBH1_VBUS, 0);
+
+ /* USB HUB RESET - De-assert USB HUB RESET_N */
+ gpio_request(EVK_USB_HUB_RESET, "usb-hub-reset");
+ gpio_direction_output(EVK_USB_HUB_RESET, 0);
+ msleep(1);
+ gpio_set_value(EVK_USB_HUB_RESET, 1);
+
+ /* Config GPIO for OTG VBus */
+ gpio_request(EVK_OTG_VBUS, "otg-vbus");
+ gpio_direction_output(EVK_OTG_VBUS, 0);
+ if (board_is_mx53_evk_a()) /*rev A,"1" disable, "0" enable vbus*/
+ gpio_set_value(EVK_OTG_VBUS, 1);
+ else if (board_is_mx53_evk_b()) /* rev B,"0" disable,"1" enable Vbus*/
+ gpio_set_value(EVK_OTG_VBUS, 0);
+
+ gpio_request(EVK_SD1_CD, "sdhc1-cd");
+ gpio_direction_input(EVK_SD1_CD); /* SD1 CD */
+ gpio_request(EVK_SD1_WP, "sdhc1-wp");
+ gpio_direction_input(EVK_SD1_WP); /* SD1 WP */
+
+ /* SD3 CD */
+ gpio_request(EVK_SD3_CD, "sdhc3-cd");
+ gpio_direction_input(EVK_SD3_CD);
+
+ /* SD3 WP */
+ gpio_request(EVK_SD3_WP, "sdhc3-wp");
+ gpio_direction_input(EVK_SD3_WP);
+
+ /* reset FEC PHY */
+ gpio_request(EVK_FEC_PHY_RESET, "fec-phy-reset");
+ gpio_direction_output(EVK_FEC_PHY_RESET, 0);
+ msleep(1);
+ gpio_set_value(EVK_FEC_PHY_RESET, 1);
+
+ gpio_request(MX53_ESAI_RESET, "fesai-reset");
+ gpio_direction_output(MX53_ESAI_RESET, 0);
+ }
+
+ /* DVI Detect */
+ gpio_request(MX53_DVI_DETECT, "dvi-detect");
+ gpio_direction_input(MX53_DVI_DETECT);
+ /* DVI Reset - Assert for i2c disabled mode */
+ gpio_request(MX53_DVI_RESET, "dvi-reset");
+ gpio_set_value(MX53_DVI_RESET, 0);
+
+ /* DVI Power-down */
+ gpio_request(MX53_DVI_PD, "dvi-pd");
+ gpio_direction_output(MX53_DVI_PD, 1);
+
+ /* DVI I2C enable */
+ gpio_request(MX53_DVI_I2C, "dvi-i2c");
+ gpio_direction_output(MX53_DVI_I2C, 0);
+
+ mxc_iomux_v3_setup_multiple_pads(mx53_nand_pads,
+ ARRAY_SIZE(mx53_nand_pads));
+
+ gpio_request(MX53_PMIC_INT, "pmic-int");
+ gpio_direction_input(MX53_PMIC_INT); /*PMIC_INT*/
+
+ /* headphone_det_b */
+ gpio_request(MX53_HP_DETECT, "hp-detect");
+ gpio_direction_input(MX53_HP_DETECT);
+
+ /* power key */
+
+ /* LCD related gpio */
+
+ /* Camera reset */
+ gpio_request(MX53_CAM_RESET, "cam-reset");
+ gpio_direction_output(MX53_CAM_RESET, 1);
+
+ /* TVIN reset */
+ gpio_request(MX53_TVIN_RESET, "tvin-reset");
+ gpio_direction_output(MX53_TVIN_RESET, 0);
+ msleep(5);
+ gpio_set_value(MX53_TVIN_RESET, 1);
+
+ /* CAN1 enable GPIO*/
+ gpio_request(MX53_CAN1_EN1, "can1-en1");
+ gpio_direction_output(MX53_CAN1_EN1, 0);
+
+ gpio_request(MX53_CAN1_EN2, "can1-en2");
+ gpio_direction_output(MX53_CAN1_EN2, 0);
+
+ /* CAN2 enable GPIO*/
+ gpio_request(MX53_CAN2_EN1, "can2-en1");
+ gpio_direction_output(MX53_CAN2_EN1, 0);
+
+ gpio_request(MX53_CAN2_EN2, "can2-en2");
+ gpio_direction_output(MX53_CAN2_EN2, 0);
+
+ if (enable_spdif) {
+ struct pad_desc spdif_pin = MX53_PAD_GPIO_19__SPDIF_TX1;
+ mxc_iomux_v3_setup_pad(&spdif_pin);
+ } else {
+ /* GPIO for 12V */
+ gpio_request(MX53_12V_EN, "12v-en");
+ gpio_direction_output(MX53_12V_EN, 0);
+ }
}
/*!
@@ -566,20 +1622,22 @@ static void __init mxc_board_init(void)
{
mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk");
mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk");
+ mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk");
+ clk_put(mxc_spdif_data.spdif_core_clk);
/* SD card detect irqs */
if (board_is_mx53_arm2()) {
- mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX53_PIN_GPIO_1);
- mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX53_PIN_GPIO_1);
+ mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ_V3(ARM2_SD1_CD);
+ mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ_V3(ARM2_SD1_CD);
mmc3_data.card_inserted_state = 1;
mmc3_data.status = NULL;
mmc3_data.wp_status = NULL;
mmc1_data.wp_status = NULL;
} else {
- mxcsdhc3_device.resource[2].start = IOMUX_TO_IRQ(MX53_PIN_EIM_DA11);
- mxcsdhc3_device.resource[2].end = IOMUX_TO_IRQ(MX53_PIN_EIM_DA11);
- mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ(MX53_PIN_EIM_DA13);
- mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ(MX53_PIN_EIM_DA13);
+ mxcsdhc3_device.resource[2].start = IOMUX_TO_IRQ_V3(EVK_SD3_CD);
+ mxcsdhc3_device.resource[2].end = IOMUX_TO_IRQ_V3(EVK_SD3_CD);
+ mxcsdhc1_device.resource[2].start = IOMUX_TO_IRQ_V3(EVK_SD1_CD);
+ mxcsdhc1_device.resource[2].end = IOMUX_TO_IRQ_V3(EVK_SD1_CD);
}
mxc_cpu_common_init();
@@ -596,7 +1654,7 @@ static void __init mxc_board_init(void)
mxc_register_device(&mxc_rtc_device, &srtc_data);
mxc_register_device(&mxc_w1_master_device, &mxc_w1_data);
mxc_register_device(&mxc_ipu_device, &mxc_ipu_data);
- mxc_register_device(&lcd_wvga_device, &lcd_wvga_data);
+ mxc_register_device(&mxc_ldb_device, &ldb_data);
mxc_register_device(&mxc_tve_device, &tve_data);
mxc_register_device(&mxcvpu_device, &mxc_vpu_data);
mxc_register_device(&gpu_device, NULL);
@@ -605,41 +1663,60 @@ static void __init mxc_board_init(void)
mxc_register_device(&mx53_lpmode_device, NULL);
mxc_register_device(&busfreq_device, NULL);
mxc_register_device(&sdram_autogating_device, NULL);
+ */
mxc_register_device(&mxc_dvfs_core_device, &dvfs_core_data);
+ mxc_register_device(&busfreq_device, NULL);
+
+ /*
mxc_register_device(&mxc_dvfs_per_device, &dvfs_per_data);
*/
+
mxc_register_device(&mxc_iim_device, NULL);
if (!board_is_mx53_arm2()) {
mxc_register_device(&mxc_pwm2_device, NULL);
mxc_register_device(&mxc_pwm_backlight_device, &mxc_pwm_backlight_data);
}
+ mxc_register_device(&mxc_flexcan0_device, &flexcan0_data);
+ mxc_register_device(&mxc_flexcan1_device, &flexcan1_data);
+
/* mxc_register_device(&mxc_keypad_device, &keypad_plat_data); */
mxc_register_device(&mxcsdhc1_device, &mmc1_data);
mxc_register_device(&mxcsdhc3_device, &mmc3_data);
mxc_register_device(&mxc_ssi1_device, NULL);
mxc_register_device(&mxc_ssi2_device, NULL);
- /*
+ mxc_register_device(&ahci_fsl_device, &sata_data);
mxc_register_device(&mxc_alsa_spdif_device, &mxc_spdif_data);
- */
- mxc_register_device(&mxc_fec_device, NULL);
-/*
- spi_register_board_info(mxc_spi_nor_device,
- ARRAY_SIZE(mxc_spi_nor_device));
-*/
-
+ if (!mxc_apc_on)
+ mxc_register_device(&mxc_fec_device, &fec_data);
+ spi_register_board_info(mxc_dataflash_device,
+ ARRAY_SIZE(mxc_dataflash_device));
i2c_register_board_info(0, mxc_i2c0_board_info,
ARRAY_SIZE(mxc_i2c0_board_info));
i2c_register_board_info(1, mxc_i2c1_board_info,
ARRAY_SIZE(mxc_i2c1_board_info));
-
+ mxc_register_device(&mxc_android_pmem_device, &android_pmem_pdata);
+ mxc_register_device(&mxc_android_pmem_gpu_device, &android_pmem_gpu_pdata);
+ mxc_register_device(&android_usb_device, &android_usb_pdata);
+ mxc_register_device(&mxc_powerkey_device, NULL);
mx53_evk_init_mc13892();
/*
pm_power_off = mxc_power_off;
*/
mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data);
+ mxc_register_device(&mxc_mlb_device, &mlb_data);
+ mx5_set_otghost_vbus_func(mx53_gpio_usbotg_driver_vbus);
mx5_usb_dr_init();
+ mx5_set_host1_vbus_func(mx53_gpio_host1_driver_vbus);
mx5_usbh1_init();
+ mxc_register_device(&mxc_nandv2_mtd_device, &mxc_nand_data);
+ if (mxc_apc_on) {
+ mxc_register_device(&mxc_esai_device, &esai_data);
+ mxc_register_device(&mxc_alsa_surround_device,
+ &mxc_surround_audio_data);
+ }
+ mxc_register_device(&mxc_v4l2_device, NULL);
+ mxc_register_device(&mxc_v4l2out_device, NULL);
}
static void __init mx53_evk_timer_init(void)
diff --git a/arch/arm/mach-mx5/mx53_evk_pmic_mc13892.c b/arch/arm/mach-mx5/mx53_evk_pmic_mc13892.c
index f8ec651cd459..be5f850fcf97 100644
--- a/arch/arm/mach-mx5/mx53_evk_pmic_mc13892.c
+++ b/arch/arm/mach-mx5/mx53_evk_pmic_mc13892.c
@@ -23,8 +23,8 @@
#include <linux/regulator/machine.h>
#include <linux/mfd/mc13892/core.h>
#include <mach/irqs.h>
-#include "iomux.h"
-#include "mx53_pins.h"
+
+#include <mach/iomux-mx53.h>
/*
* Convenience conversion.
@@ -183,6 +183,8 @@ static struct regulator_init_data vvideo_init = {
.min_uV = mV_to_uV(2500),
.max_uV = mV_to_uV(2775),
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
}
};
@@ -266,7 +268,7 @@ static struct regulator_init_data gpo4_init = {
.name = "GPO4",
}
};
-
+#if 0
/*!
* the event handler for power on event
*/
@@ -274,20 +276,20 @@ static void power_on_evt_handler(void)
{
pr_info("pwr on event1 is received \n");
}
-
+#endif
static int mc13892_regulator_init(struct mc13892 *mc13892)
{
unsigned int value;
- pmic_event_callback_t power_key_event;
+// pmic_event_callback_t power_key_event;
int register_mask;
pr_info("Initializing regulators for MX53 EVK \n");
-
+#if 0
/* subscribe PWRON1 event to enable ON_OFF key */
power_key_event.param = NULL;
power_key_event.func = (void *)power_on_evt_handler;
pmic_event_subscribe(EVENT_PWRONI, power_key_event);
-
+#endif
/* Bit 4 DRM: keep VSRTC and CLK32KMCU on for all states */
#if defined(CONFIG_RTC_DRV_MXC_V2) || defined(CONFIG_RTC_DRV_MXC_V2_MODULE)
value = BITFVAL(DRM, 1);
@@ -337,7 +339,7 @@ static struct mc13892_platform_data mc13892_plat = {
static struct i2c_board_info __initdata mc13892_i2c_device = {
I2C_BOARD_INFO("mc13892", 0x08),
- .irq = IOMUX_TO_IRQ(MX53_PIN_GPIO_16),
+ .irq = IOMUX_TO_IRQ_V3(203),
.platform_data = &mc13892_plat,
};
diff --git a/arch/arm/mach-mx5/pm.c b/arch/arm/mach-mx5/pm.c
index a63d6e725e8f..b2bf2f8355fd 100644
--- a/arch/arm/mach-mx5/pm.c
+++ b/arch/arm/mach-mx5/pm.c
@@ -25,9 +25,15 @@
#include <asm/tlb.h>
#include <asm/mach/map.h>
#include <mach/hardware.h>
-#include "crm_regs.h"
#include "mach/irqs.h"
+#define MXC_SRPG_EMPGC0_SRPGCR (IO_ADDRESS(GPC_BASE_ADDR) + 0x2C0)
+#define MXC_SRPG_EMPGC1_SRPGCR (IO_ADDRESS(GPC_BASE_ADDR) + 0x2D0)
+#define DATABAHN_CTL_REG0 0
+#define DATABAHN_CTL_REG19 0x4c
+#define DATABAHN_CTL_REG79 0x13c
+#define DATABAHN_PHY_REG25 0x264
+
static struct cpu_wp *cpu_wp_tbl;
static struct clk *cpu_clk;
@@ -41,16 +47,17 @@ extern int set_cpu_freq(int wp);
static struct device *pm_dev;
struct clk *gpc_dvfs_clk;
extern void cpu_do_suspend_workaround(u32 sdclk_iomux_addr);
-extern void cpu_cortexa8_do_idle(void *);
+extern void mx50_suspend(u32 databahn_addr);
extern struct cpu_wp *(*get_cpu_wp)(int *wp);
+extern void __iomem *databahn_base;
extern int iram_ready;
void *suspend_iram_base;
void (*suspend_in_iram)(void *sdclk_iomux_addr) = NULL;
+void __iomem *suspend_param1;
-static int mx51_suspend_enter(suspend_state_t state)
+static int mx5_suspend_enter(suspend_state_t state)
{
- void __iomem *sdclk_iomux_addr = IO_ADDRESS(IOMUXC_BASE_ADDR + 0x4b8);
u32 * wake_src;
/* Check that we have a wake up source. We don't want to suspend if not.*/
@@ -82,12 +89,15 @@ static int mx51_suspend_enter(suspend_state_t state)
local_flush_tlb_all();
flush_cache_all();
- /* Run the suspend code from iRAM. */
- suspend_in_iram(sdclk_iomux_addr);
+ if (cpu_is_mx51() || cpu_is_mx53()) {
+ /* Run the suspend code from iRAM. */
+ suspend_in_iram(suspend_param1);
- /*clear the EMPGC0/1 bits */
- __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR);
- __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR);
+ /*clear the EMPGC0/1 bits */
+ __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR);
+ __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR);
+ } else
+ suspend_in_iram(databahn_base);
} else {
cpu_do_idle();
}
@@ -99,7 +109,7 @@ static int mx51_suspend_enter(suspend_state_t state)
/*
* Called after processes are frozen, but before we shut down devices.
*/
-static int mx51_suspend_prepare(void)
+static int mx5_suspend_prepare(void)
{
#if defined(CONFIG_CPU_FREQ)
struct cpufreq_freqs freqs;
@@ -122,7 +132,7 @@ static int mx51_suspend_prepare(void)
/*
* Called before devices are re-setup.
*/
-static void mx51_suspend_finish(void)
+static void mx5_suspend_finish(void)
{
#if defined(CONFIG_CPU_FREQ)
struct cpufreq_freqs freqs;
@@ -145,35 +155,35 @@ static void mx51_suspend_finish(void)
/*
* Called after devices are re-setup, but before processes are thawed.
*/
-static void mx51_suspend_end(void)
+static void mx5_suspend_end(void)
{
}
-static int mx51_pm_valid(suspend_state_t state)
+static int mx5_pm_valid(suspend_state_t state)
{
return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX);
}
-struct platform_suspend_ops mx51_suspend_ops = {
- .valid = mx51_pm_valid,
- .prepare = mx51_suspend_prepare,
- .enter = mx51_suspend_enter,
- .finish = mx51_suspend_finish,
- .end = mx51_suspend_end,
+struct platform_suspend_ops mx5_suspend_ops = {
+ .valid = mx5_pm_valid,
+ .prepare = mx5_suspend_prepare,
+ .enter = mx5_suspend_enter,
+ .finish = mx5_suspend_finish,
+ .end = mx5_suspend_end,
};
-static int __devinit mx51_pm_probe(struct platform_device *pdev)
+static int __devinit mx5_pm_probe(struct platform_device *pdev)
{
pm_dev = &pdev->dev;
return 0;
}
-static struct platform_driver mx51_pm_driver = {
+static struct platform_driver mx5_pm_driver = {
.driver = {
- .name = "mx51_pm",
+ .name = "mx5_pm",
},
- .probe = mx51_pm_probe,
+ .probe = mx5_pm_probe,
};
static int __init pm_init(void)
@@ -181,19 +191,32 @@ static int __init pm_init(void)
int cpu_wp_nr;
unsigned long iram_paddr;
- pr_info("Static Power Management for Freescale i.MX51\n");
- if (platform_driver_register(&mx51_pm_driver) != 0) {
- printk(KERN_ERR "mx51_pm_driver register failed\n");
+ pr_info("Static Power Management for Freescale i.MX5\n");
+ if (platform_driver_register(&mx5_pm_driver) != 0) {
+ printk(KERN_ERR "mx5_pm_driver register failed\n");
return -ENODEV;
}
- suspend_set_ops(&mx51_suspend_ops);
+ suspend_set_ops(&mx5_suspend_ops);
/* Move suspend routine into iRAM */
iram_alloc(SZ_4K, &iram_paddr);
/* Need to remap the area here since we want the memory region
to be executable. */
suspend_iram_base = __arm_ioremap(iram_paddr, SZ_4K,
MT_HIGH_VECTORS);
- memcpy(suspend_iram_base, cpu_do_suspend_workaround, SZ_4K);
+
+ if (cpu_is_mx51() || cpu_is_mx53()) {
+ suspend_param1 = IO_ADDRESS(IOMUXC_BASE_ADDR + 0x4b8);
+ memcpy(suspend_iram_base, cpu_do_suspend_workaround,
+ SZ_4K);
+ } else if (cpu_is_mx50()) {
+ /*
+ * Need to run the suspend code from IRAM as the DDR needs
+ * to be put into self refresh mode manually.
+ */
+ memcpy(suspend_iram_base, mx50_suspend, SZ_4K);
+
+ suspend_param1 = databahn_base;
+ }
suspend_in_iram = (void *)suspend_iram_base;
cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr);
@@ -212,7 +235,7 @@ static int __init pm_init(void)
static void __exit pm_cleanup(void)
{
/* Unregister the device structure */
- platform_driver_unregister(&mx51_pm_driver);
+ platform_driver_unregister(&mx5_pm_driver);
}
module_init(pm_init);
diff --git a/arch/arm/mach-mx5/sdram_autogating.c b/arch/arm/mach-mx5/sdram_autogating.c
index fa9f0ccfe283..0b05d791c4f9 100644
--- a/arch/arm/mach-mx5/sdram_autogating.c
+++ b/arch/arm/mach-mx5/sdram_autogating.c
@@ -80,6 +80,8 @@ int sdram_autogating_active()
void start_sdram_autogating()
{
+ if (cpu_is_mx50())
+ return;
if (sdram_autogating_paused) {
enable();
sdram_autogating_paused = 0;
@@ -88,6 +90,9 @@ void start_sdram_autogating()
void stop_sdram_autogating()
{
+ if (cpu_is_mx50())
+ return;
+
if (sdram_autogating_is_active) {
sdram_autogating_paused = 1;
disable();
diff --git a/arch/arm/mach-mx5/serial.c b/arch/arm/mach-mx5/serial.c
index 053829cd3b4e..6d01de55c50b 100644
--- a/arch/arm/mach-mx5/serial.c
+++ b/arch/arm/mach-mx5/serial.c
@@ -23,7 +23,6 @@
#include <mach/hardware.h>
#include <mach/mxc_uart.h>
#include "serial.h"
-#include "board-mx53_evk.h"
#if defined(CONFIG_SERIAL_MXC) || defined(CONFIG_SERIAL_MXC_MODULE)
@@ -42,13 +41,12 @@ static uart_mxc_port mxc_ports[] = {
.flags = ASYNC_BOOT_AUTOCONF,
.line = 0,
},
- .ints_muxed = UART1_MUX_INTS,
+ .ints_muxed = 1,
.mode = UART1_MODE,
.ir_mode = UART1_IR,
.enabled = UART1_ENABLED,
- .hardware_flow = UART1_HW_FLOW,
.cts_threshold = UART1_UCR4_CTSTL,
- .dma_enabled = UART1_DMA_ENABLE,
+ .dma_enabled = UART1_DMA_ENABLED,
.dma_rxbuf_size = UART1_DMA_RXBUFSIZE,
.rx_threshold = UART1_UFCR_RXTL,
.tx_threshold = UART1_UFCR_TXTL,
@@ -63,13 +61,12 @@ static uart_mxc_port mxc_ports[] = {
.flags = ASYNC_BOOT_AUTOCONF,
.line = 1,
},
- .ints_muxed = UART2_MUX_INTS,
+ .ints_muxed = 1,
.mode = UART2_MODE,
.ir_mode = UART2_IR,
.enabled = UART2_ENABLED,
- .hardware_flow = UART2_HW_FLOW,
.cts_threshold = UART2_UCR4_CTSTL,
- .dma_enabled = UART2_DMA_ENABLE,
+ .dma_enabled = UART2_DMA_ENABLED,
.dma_rxbuf_size = UART2_DMA_RXBUFSIZE,
.rx_threshold = UART2_UFCR_RXTL,
.tx_threshold = UART2_UFCR_TXTL,
@@ -84,13 +81,12 @@ static uart_mxc_port mxc_ports[] = {
.flags = ASYNC_BOOT_AUTOCONF,
.line = 2,
},
- .ints_muxed = UART3_MUX_INTS,
+ .ints_muxed = 1,
.mode = UART3_MODE,
.ir_mode = UART3_IR,
.enabled = UART3_ENABLED,
- .hardware_flow = UART3_HW_FLOW,
.cts_threshold = UART3_UCR4_CTSTL,
- .dma_enabled = UART3_DMA_ENABLE,
+ .dma_enabled = UART3_DMA_ENABLED,
.dma_rxbuf_size = UART3_DMA_RXBUFSIZE,
.rx_threshold = UART3_UFCR_RXTL,
.tx_threshold = UART3_UFCR_TXTL,
@@ -105,13 +101,11 @@ static uart_mxc_port mxc_ports[] = {
.flags = ASYNC_BOOT_AUTOCONF,
.line = 3,
},
- .ints_muxed = UART4_MUX_INTS,
- .mode = UART4_MODE,
- .ir_mode = UART4_IR,
- .enabled = UART4_ENABLED,
- .hardware_flow = UART4_HW_FLOW,
+ .ints_muxed = 1,
+ .mode = MODE_DCE,
+ .ir_mode = NO_IRDA,
+ .enabled = 1,
.cts_threshold = UART4_UCR4_CTSTL,
- .dma_enabled = UART4_DMA_ENABLE,
.dma_rxbuf_size = UART4_DMA_RXBUFSIZE,
.rx_threshold = UART4_UFCR_RXTL,
.tx_threshold = UART4_UFCR_TXTL,
@@ -126,13 +120,11 @@ static uart_mxc_port mxc_ports[] = {
.flags = ASYNC_BOOT_AUTOCONF,
.line = 4,
},
- .ints_muxed = UART5_MUX_INTS,
- .mode = UART5_MODE,
- .ir_mode = UART5_IR,
- .enabled = UART5_ENABLED,
- .hardware_flow = UART5_HW_FLOW,
+ .ints_muxed = 1,
+ .mode = MODE_DCE,
+ .ir_mode = NO_IRDA,
+ .enabled = 1,
.cts_threshold = UART5_UCR4_CTSTL,
- .dma_enabled = UART5_DMA_ENABLE,
.dma_rxbuf_size = UART5_DMA_RXBUFSIZE,
.rx_threshold = UART5_UFCR_RXTL,
.tx_threshold = UART5_UFCR_TXTL,
@@ -149,18 +141,9 @@ static struct resource mxc_uart_resources1[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = UART1_INT1,
+ .start = MXC_INT_UART1,
.flags = IORESOURCE_IRQ,
},
- {
- .start = UART1_INT2,
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = UART1_INT3,
- .flags = IORESOURCE_IRQ,
- },
-
};
static struct platform_device mxc_uart_device1 = {
@@ -180,15 +163,7 @@ static struct resource mxc_uart_resources2[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = UART2_INT1,
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = UART2_INT2,
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = UART2_INT3,
+ .start = MXC_INT_UART2,
.flags = IORESOURCE_IRQ,
},
};
@@ -210,15 +185,7 @@ static struct resource mxc_uart_resources3[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = UART3_INT1,
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = UART3_INT2,
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = UART3_INT3,
+ .start = MXC_INT_UART3,
.flags = IORESOURCE_IRQ,
},
};
@@ -240,15 +207,7 @@ static struct resource mxc_uart_resources4[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = UART4_INT1,
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = UART4_INT2,
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = UART4_INT3,
+ .start = MXC_INT_UART4,
.flags = IORESOURCE_IRQ,
},
};
@@ -270,15 +229,7 @@ static struct resource mxc_uart_resources5[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = UART5_INT1,
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = UART5_INT2,
- .flags = IORESOURCE_IRQ,
- },
- {
- .start = UART5_INT3,
+ .start = MXC_INT_UART5,
.flags = IORESOURCE_IRQ,
},
};
@@ -295,7 +246,7 @@ static struct platform_device mxc_uart_device5 = {
static int __init mxc_init_uart(void)
{
- if (cpu_is_mx53()) {
+ if (cpu_is_mx53() || cpu_is_mx50()) {
mxc_uart_resources1[0].start -= 0x20000000;
mxc_uart_resources1[0].end -= 0x20000000;
mxc_uart_resources2[0].start -= 0x20000000;
@@ -311,16 +262,10 @@ static int __init mxc_init_uart(void)
/* Register all the MXC UART platform device structures */
platform_device_register(&mxc_uart_device1);
platform_device_register(&mxc_uart_device2);
-#if UART3_ENABLED == 1
platform_device_register(&mxc_uart_device3);
-#endif /* UART3_ENABLED */
if (cpu_is_mx53()) {
-#if UART4_ENABLED == 1
platform_device_register(&mxc_uart_device4);
-#endif /* UART4_ENABLED */
-#if UART5_ENABLED == 1
platform_device_register(&mxc_uart_device5);
-#endif /* UART5_ENABLED */
}
return 0;
}
diff --git a/arch/arm/mach-mx5/serial.h b/arch/arm/mach-mx5/serial.h
index aa97228e3865..b74cd0b2661c 100644
--- a/arch/arm/mach-mx5/serial.h
+++ b/arch/arm/mach-mx5/serial.h
@@ -14,17 +14,8 @@
#ifndef __ARCH_ARM_MACH_MX51_SERIAL_H__
#define __ARCH_ARM_MACH_MX51_SERIAL_H__
-#include <mach/mxc_uart.h>
-
/* UART 1 configuration */
/*!
- * This option allows to choose either an interrupt-driven software controlled
- * hardware flow control (set this option to 0) or hardware-driven hardware
- * flow control (set this option to 1).
- */
-/* UART used as wakeup source */
-#define UART1_HW_FLOW 0
-/*!
* This specifies the threshold at which the CTS pin is deasserted by the
* RXFIFO. Set this value in Decimal to anything from 0 to 32 for
* hardware-driven hardware flow control. Read the HW spec while specifying
@@ -33,10 +24,6 @@
*/
#define UART1_UCR4_CTSTL 16
/*!
- * This is option to enable (set this option to 1) or disable DMA data transfer
- */
-#define UART1_DMA_ENABLE 0
-/*!
* Specify the size of the DMA receive buffer. The minimum buffer size is 512
* bytes. The buffer size should be a multiple of 256.
*/
@@ -56,88 +43,28 @@
*/
#define UART1_UFCR_TXTL 16
/* UART 2 configuration */
-#define UART2_HW_FLOW 0
-#define UART2_UCR4_CTSTL -1
-#define UART2_DMA_ENABLE 0
+#define UART2_UCR4_CTSTL 16
#define UART2_DMA_RXBUFSIZE 512
#define UART2_UFCR_RXTL 16
#define UART2_UFCR_TXTL 16
/* UART 3 configuration */
-#define UART3_HW_FLOW 1
#define UART3_UCR4_CTSTL 16
-#define UART3_DMA_ENABLE 1
#define UART3_DMA_RXBUFSIZE 1024
#define UART3_UFCR_RXTL 16
#define UART3_UFCR_TXTL 16
/* UART 4 configuration */
-#define UART4_HW_FLOW 0
#define UART4_UCR4_CTSTL -1
-#define UART4_DMA_ENABLE 0
#define UART4_DMA_RXBUFSIZE 512
#define UART4_UFCR_RXTL 16
#define UART4_UFCR_TXTL 16
/* UART 5 configuration */
-#define UART5_HW_FLOW 0
#define UART5_UCR4_CTSTL -1
-#define UART5_DMA_ENABLE 0
#define UART5_DMA_RXBUFSIZE 512
#define UART5_UFCR_RXTL 16
#define UART5_UFCR_TXTL 16
-/*
- * UART Chip level Configuration that a user may not have to edit. These
- * configuration vary depending on how the UART module is integrated with
- * the ARM core
- */
-/*
- * Is the MUXED interrupt output sent to the ARM core
- */
-#define INTS_NOTMUXED 0
-#define INTS_MUXED 1
-/* UART 1 configuration */
-/*!
- * This define specifies whether the muxed ANDed interrupt line or the
- * individual interrupts from the UART port is integrated with the ARM core.
- * There exists a define like this for each UART port. Valid values that can
- * be used are \b INTS_NOTMUXED or \b INTS_MUXED.
- */
-#define UART1_MUX_INTS INTS_MUXED
-/*!
- * This define specifies the transmitter interrupt number or the interrupt
- * number of the ANDed interrupt in case the interrupts are muxed. There exists
- * a define like this for each UART port.
- */
-#define UART1_INT1 MXC_INT_UART1
-/*!
- * This define specifies the receiver interrupt number. If the interrupts of
- * the UART are muxed, then we specify here a dummy value -1. There exists a
- * define like this for each UART port.
- */
-#define UART1_INT2 -1
-/*!
- * This specifies the master interrupt number. If the interrupts of the UART
- * are muxed, then we specify here a dummy value of -1. There exists a define
- * like this for each UART port.
- */
-#define UART1_INT3 -1
-/* UART 2 configuration */
-#define UART2_MUX_INTS INTS_MUXED
-#define UART2_INT1 MXC_INT_UART2
-#define UART2_INT2 -1
-#define UART2_INT3 -1
-/* UART 3 configuration */
-#define UART3_MUX_INTS INTS_MUXED
-#define UART3_INT1 MXC_INT_UART3
-#define UART3_INT2 -1
-#define UART3_INT3 -1
-/* UART 4 configuration */
-#define UART4_MUX_INTS INTS_MUXED
-#define UART4_INT1 MXC_INT_UART4
-#define UART4_INT2 -1
-#define UART4_INT3 -1
-/* UART 5 configuration */
-#define UART5_MUX_INTS INTS_MUXED
-#define UART5_INT1 MXC_INT_UART5
-#define UART5_INT2 -1
-#define UART5_INT3 -1
+
+#ifdef CONFIG_MODULE_CCXMX51
+#include "board-ccwmx51.h"
+#endif
#endif /* __ARCH_ARM_MACH_MX51_SERIAL_H__ */
diff --git a/arch/arm/mach-mx5/system.c b/arch/arm/mach-mx5/system.c
index 669be9c4c9cb..199c30e26947 100644
--- a/arch/arm/mach-mx5/system.c
+++ b/arch/arm/mach-mx5/system.c
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <asm/io.h>
#include <mach/hardware.h>
+#include <mach/clock.h>
#include <asm/proc-fns.h>
#include <asm/system.h>
#include "crm_regs.h"
@@ -33,10 +34,13 @@
extern int mxc_jtag_enabled;
extern int iram_ready;
-static struct clk *gpc_dvfs_clk;
-
-extern void cpu_cortexa8_do_idle(void *addr);
+extern void __iomem *ccm_base;
+extern void __iomem *databahn_base;
+extern void (*wait_in_iram)(void *ccm_addr, void *databahn_addr);
+extern void *wait_in_iram_base;
+extern void mx50_wait(u32 ccm_base, u32 databahn_addr);
+static struct clk *gpc_dvfs_clk;
/* set cpu low power mode before WFI instruction */
void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
@@ -66,6 +70,7 @@ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
if (mode == WAIT_UNCLOCKED_POWER_OFF) {
ccm_clpcr |= (0x1 << MXC_CCM_CLPCR_LPM_OFFSET);
ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY;
+ ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS;
stop_mode = 0;
} else {
ccm_clpcr |= (0x2 << MXC_CCM_CLPCR_LPM_OFFSET);
@@ -96,7 +101,8 @@ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
__raw_writel(ccm_clpcr, MXC_CCM_CLPCR);
if (cpu_is_mx51())
__raw_writel(arm_srpgcr, MXC_SRPG_ARM_SRPGCR);
- __raw_writel(arm_srpgcr, MXC_SRPG_NEON_SRPGCR);
+ if (!cpu_is_mx50())
+ __raw_writel(arm_srpgcr, MXC_SRPG_NEON_SRPGCR);
if (stop_mode) {
__raw_writel(empgc0, MXC_SRPG_EMPGC0_SRPGCR);
__raw_writel(empgc1, MXC_SRPG_EMPGC1_SRPGCR);
@@ -150,14 +156,21 @@ static int arch_idle_mode = WAIT_UNCLOCKED_POWER_OFF;
*/
void arch_idle(void)
{
- if (likely(!mxc_jtag_enabled)) {
+/* if (likely(!mxc_jtag_enabled)) */{
+ struct clk *ddr_clk = clk_get(NULL, "ddr_clk");
if (gpc_dvfs_clk == NULL)
gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs_clk");
/* gpc clock is needed for SRPG */
clk_enable(gpc_dvfs_clk);
mxc_cpu_lp_set(arch_idle_mode);
- cpu_do_idle();
+ if (cpu_is_mx50() && (clk_get_usecount(ddr_clk) == 0)) {
+ memcpy(wait_in_iram_base, mx50_wait, SZ_4K);
+ wait_in_iram = (void *)wait_in_iram_base;
+ wait_in_iram(ccm_base, databahn_base);
+ } else
+ cpu_do_idle();
clk_disable(gpc_dvfs_clk);
+ clk_put(ddr_clk);
}
}
@@ -171,8 +184,99 @@ void arch_reset(char mode)
/* Workaround to reset NFC_CONFIG3 register
* due to the chip warm reset does not reset it
*/
- __raw_writel(0x20600, IO_ADDRESS(NFC_BASE_ADDR) + 0x28);
+ if (cpu_is_mx51() || cpu_is_mx53())
+ __raw_writel(0x20600, IO_ADDRESS(NFC_BASE_ADDR) + 0x28);
/* Assert SRS signal */
mxc_wd_reset();
}
+
+
+static int __mxs_reset_block(void __iomem *hwreg, int just_enable)
+{
+ u32 c;
+ int timeout;
+
+ /* the process of software reset of IP block is done
+ in several steps:
+
+ - clear SFTRST and wait for block is enabled;
+ - clear clock gating (CLKGATE bit);
+ - set the SFTRST again and wait for block is in reset;
+ - clear SFTRST and wait for reset completion.
+ */
+ c = __raw_readl(hwreg);
+ c &= ~(1 << 31); /* clear SFTRST */
+ __raw_writel(c, hwreg);
+ for (timeout = 1000000; timeout > 0; timeout--)
+ /* still in SFTRST state ? */
+ if ((__raw_readl(hwreg) & (1 << 31)) == 0)
+ break;
+ if (timeout <= 0) {
+ printk(KERN_ERR "%s(%p): timeout when enabling\n",
+ __func__, hwreg);
+ return -ETIME;
+ }
+
+ c = __raw_readl(hwreg);
+ c &= ~(1 << 30); /* clear CLKGATE */
+ __raw_writel(c, hwreg);
+
+ if (!just_enable) {
+ c = __raw_readl(hwreg);
+ c |= (1 << 31); /* now again set SFTRST */
+ __raw_writel(c, hwreg);
+ for (timeout = 1000000; timeout > 0; timeout--)
+ /* poll until CLKGATE set */
+ if (__raw_readl(hwreg) & (1 << 30))
+ break;
+ if (timeout <= 0) {
+ printk(KERN_ERR "%s(%p): timeout when resetting\n",
+ __func__, hwreg);
+ return -ETIME;
+ }
+
+ c = __raw_readl(hwreg);
+ c &= ~(1 << 31); /* clear SFTRST */
+ __raw_writel(c, hwreg);
+ for (timeout = 1000000; timeout > 0; timeout--)
+ /* still in SFTRST state ? */
+ if ((__raw_readl(hwreg) & (1 << 31)) == 0)
+ break;
+ if (timeout <= 0) {
+ printk(KERN_ERR "%s(%p): timeout when enabling "
+ "after reset\n", __func__, hwreg);
+ return -ETIME;
+ }
+
+ c = __raw_readl(hwreg);
+ c &= ~(1 << 30); /* clear CLKGATE */
+ __raw_writel(c, hwreg);
+ }
+ for (timeout = 1000000; timeout > 0; timeout--)
+ /* still in SFTRST state ? */
+ if ((__raw_readl(hwreg) & (1 << 30)) == 0)
+ break;
+
+ if (timeout <= 0) {
+ printk(KERN_ERR "%s(%p): timeout when unclockgating\n",
+ __func__, hwreg);
+ return -ETIME;
+ }
+
+ return 0;
+}
+
+int mxs_reset_block(void __iomem *hwreg, int just_enable)
+{
+ int try = 10;
+ int r;
+
+ while (try--) {
+ r = __mxs_reset_block(hwreg, just_enable);
+ if (!r)
+ break;
+ pr_debug("%s: try %d failed\n", __func__, 10 - try);
+ }
+ return r;
+}
diff --git a/arch/arm/mach-mx5/usb.h b/arch/arm/mach-mx5/usb.h
index f451e6fe8582..6115d3375c05 100644
--- a/arch/arm/mach-mx5/usb.h
+++ b/arch/arm/mach-mx5/usb.h
@@ -30,6 +30,9 @@ extern void __init mx5_usb_dr_init(void);
extern void __init mx5_usbh1_init(void);
extern void __init mx5_usbh2_init(void);
+typedef void (*driver_vbus_func)(bool);
+extern void mx5_set_host1_vbus_func(driver_vbus_func);
+extern void mx5_set_otghost_vbus_func(driver_vbus_func);
/*
* Used to set pdata->operating_mode before registering the platform_device.
* If OTG is configured, the controller operates in OTG mode,
diff --git a/arch/arm/mach-mx5/usb_dr.c b/arch/arm/mach-mx5/usb_dr.c
index 658583b65ab6..4f36379b8d64 100644
--- a/arch/arm/mach-mx5/usb_dr.c
+++ b/arch/arm/mach-mx5/usb_dr.c
@@ -18,12 +18,12 @@
#include <linux/fsl_devices.h>
#include <mach/arc_otg.h>
#include <mach/hardware.h>
+#include <asm/delay.h>
#include "usb.h"
#if defined(CONFIG_USB_OTG) || defined(CONFIG_USB_EHCI_ARC_OTG) || defined(CONFIG_USB_GADGET_ARC)
static int usbotg_init_ext(struct platform_device *pdev);
static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata);
-static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable);
static void usbotg_clock_gate(bool on);
/*
@@ -40,7 +40,6 @@ static struct fsl_usb2_platform_data dr_utmi_config = {
.gpio_usb_active = gpio_usbotg_hs_active,
.gpio_usb_inactive = gpio_usbotg_hs_inactive,
.usb_clock_for_pm = usbotg_clock_gate,
- .wake_up_enable = _wake_up_enable,
.transceiver = "utmi",
};
@@ -48,6 +47,13 @@ static struct fsl_usb2_platform_data dr_utmi_config = {
static int usbotg_init_ext(struct platform_device *pdev)
{
struct clk *usb_clk;
+ if (cpu_is_mx50()) {
+ usb_clk = clk_get(&pdev->dev, "usb_phy1_clk");
+ clk_enable(usb_clk);
+ clk_put(usb_clk);
+
+ return usbotg_init(pdev);
+ }
usb_clk = clk_get(NULL, "usboh3_clk");
clk_enable(usb_clk);
@@ -69,6 +75,15 @@ static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata)
{
struct clk *usb_clk;
+ if (cpu_is_mx50()) {
+ usb_clk = clk_get(&pdata->pdev->dev, "usb_phy1_clk");
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
+
+ usbotg_uninit(pdata);
+ return;
+ }
+
usb_clk = clk_get(NULL, "usboh3_clk");
clk_disable(usb_clk);
clk_put(usb_clk);
@@ -80,33 +95,149 @@ static void usbotg_uninit_ext(struct fsl_usb2_platform_data *pdata)
usbotg_uninit(pdata);
}
-static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable)
+#define ENABLED_BY_HOST (0x1 << 0)
+#define ENABLED_BY_DEVICE (0x1 << 1)
+#if defined(CONFIG_USB_EHCI_ARC_OTG) && defined(CONFIG_USB_GADGET_ARC)
+/* Below two macros are used at otg mode to indicate usb mode*/
+static u32 wakeup_irq_enable_src = 0;
+static void __wakeup_irq_enable(bool on, int source)
{
- if (get_usb_mode(pdata) == FSL_USB_DR_DEVICE) {
- if (enable) {
+ /* otg host and device share the OWIE bit, only when host and device
+ * all enable the wakeup irq, we can enable the OWIE bit
+ */
+ if (on) {
+ wakeup_irq_enable_src |= source;
+ if (wakeup_irq_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) {
USBCTRL |= UCTRL_OWIE;
- USBCTRL_HOST2 |= UCTRL_H2OVBWK_EN;
USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_CONF2;
- } else {
- USBCTRL &= ~UCTRL_OWIE;
- USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN;
- USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CONF2;
+ printk("OTG wakeup irq is enabled\n");
}
- } else {
- if (enable) {
- USBCTRL |= UCTRL_OWIE;
- USBCTRL_HOST2 |= (1 << 5);
- } else {
- USBCTRL &= ~UCTRL_OWIE;
- USBCTRL_HOST2 &= ~(1 << 5);
+ }else {
+ printk("OTG wakeup irq disable\n");
+ USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CONF2;
+ USBCTRL &= ~UCTRL_OWIE;
+ wakeup_irq_enable_src &= ~source;
+ /* The interrupt must be disabled for at least 3 clock
+ * cycles of the standby clock(32k Hz) , that is 0.094 ms*/
+ udelay(100);
+ }
+}
+#else
+static void __wakeup_irq_enable(bool on, int source)
+{
+ if (on) {
+ USBCTRL |= UCTRL_OWIE;
+ USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_CONF2;
+ }else {
+ USBCTRL &= ~UCTRL_OWIE;
+ USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CONF2;
+ /* The interrupt must be disabled for at least 3 clock
+ * cycles of the standby clock(32k Hz) , that is 0.094 ms*/
+ udelay(100);
+ }
+}
+#endif
+
+#ifdef CONFIG_USB_EHCI_ARC_OTG
+static void _host_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ __wakeup_irq_enable(enable, ENABLED_BY_HOST);
+ /* host only care the ID change wakeup event */
+ if (enable) {
+ USBCTRL_HOST2 |= UCTRL_H2OIDWK_EN;
+ }else {
+ USBCTRL_HOST2 &= ~UCTRL_H2OIDWK_EN;
+ /* The interrupt must be disabled for at least 2 clock
+ * cycles of the standby clock(32k Hz) , that is 0.0625 ms*/
+ udelay(100);
+ }
+}
+#endif
+
+#ifdef CONFIG_USB_GADGET_ARC
+static void _device_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ __wakeup_irq_enable(enable, ENABLED_BY_DEVICE);
+ /* if udc is not used by any gadget, we can not enable the vbus wakeup */
+ if (!pdata->port_enables)
+ {
+ USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN;
+ return;
+ }
+ if (enable) {
+ USBCTRL_HOST2 |= UCTRL_H2OVBWK_EN;
+ }else {
+ USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN;
+ }
+}
+#endif
+
+#if defined(CONFIG_USB_EHCI_ARC_OTG) && defined(CONFIG_USB_GADGET_ARC)
+static u32 low_power_enable_src = 0;
+static void __phy_lowpower_suspend(bool enable, int source)
+{
+ if (enable) {
+ low_power_enable_src |= source;
+ if (low_power_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) {
+ UOG_PORTSC1 |= PORTSC_PHCD;
+ printk("OTG phy lowpower enable\n");
}
+ }else {
+ printk("OTG phy lowpower disable\n");
+ UOG_PORTSC1 &= ~PORTSC_PHCD;
+ low_power_enable_src &= ~source;
+ }
+}
+#else
+static void __phy_lowpower_suspend(bool enable, int source)
+{
+ if (enable) {
+ UOG_PORTSC1 |= PORTSC_PHCD;
+ }else {
+ UOG_PORTSC1 &= ~PORTSC_PHCD;
}
}
+#endif
+
+#ifdef CONFIG_USB_EHCI_ARC_OTG
+static void _host_phy_lowpower_suspend(bool enable)
+{
+ __phy_lowpower_suspend(enable, ENABLED_BY_HOST);
+}
+#endif
+
+#ifdef CONFIG_USB_GADGET_ARC
+static void _device_phy_lowpower_suspend(bool enable)
+{
+ __phy_lowpower_suspend(enable, ENABLED_BY_DEVICE);
+}
+#endif
static void usbotg_clock_gate(bool on)
{
struct clk *usb_clk;
+ if (cpu_is_mx50()) {
+ if (on) {
+ usb_clk = clk_get(NULL, "usb_ahb_clk");
+ clk_enable(usb_clk);
+ clk_put(usb_clk);
+
+ usb_clk = clk_get(NULL, "usb_phy1_clk");
+ clk_enable(usb_clk);
+ clk_put(usb_clk);
+ } else {
+ usb_clk = clk_get(NULL, "usb_phy1_clk");
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
+
+ usb_clk = clk_get(NULL, "usb_ahb_clk");
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
+ }
+ return;
+ }
+
if (on) {
usb_clk = clk_get(NULL, "usb_ahb_clk");
clk_enable(usb_clk);
@@ -140,6 +271,13 @@ static void usbotg_clock_gate(bool on)
}
#endif
+void mx5_set_otghost_vbus_func(driver_vbus_func driver_vbus)
+{
+#if defined(CONFIG_USB_OTG) || defined(CONFIG_USB_EHCI_ARC_OTG) || defined(CONFIG_USB_GADGET_ARC)
+ dr_utmi_config.platform_driver_vbus = driver_vbus;
+#endif
+}
+
void __init mx5_usb_dr_init(void)
{
#ifdef CONFIG_USB_OTG
@@ -149,11 +287,15 @@ void __init mx5_usb_dr_init(void)
#endif
#ifdef CONFIG_USB_EHCI_ARC_OTG
dr_utmi_config.operating_mode = DR_HOST_MODE;
+ dr_utmi_config.wake_up_enable = _host_wakeup_enable;
+ dr_utmi_config.phy_lowpower_suspend = _host_phy_lowpower_suspend;
platform_device_add_data(&mxc_usbdr_host_device, &dr_utmi_config, sizeof(dr_utmi_config));
platform_device_register(&mxc_usbdr_host_device);
#endif
#ifdef CONFIG_USB_GADGET_ARC
dr_utmi_config.operating_mode = DR_UDC_MODE;
+ dr_utmi_config.wake_up_enable = _device_wakeup_enable;
+ dr_utmi_config.phy_lowpower_suspend = _device_phy_lowpower_suspend;
platform_device_add_data(&mxc_usbdr_udc_device, &dr_utmi_config, sizeof(dr_utmi_config));
platform_device_register(&mxc_usbdr_udc_device);
#endif
diff --git a/arch/arm/mach-mx5/usb_h1.c b/arch/arm/mach-mx5/usb_h1.c
index 7f0c463d45c1..3c53ed8901ae 100644
--- a/arch/arm/mach-mx5/usb_h1.c
+++ b/arch/arm/mach-mx5/usb_h1.c
@@ -17,14 +17,15 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
+#include <asm/delay.h>
#include <mach/arc_otg.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include "usb.h"
#include "iomux.h"
#include "mx51_pins.h"
-
-
+//#undef pr_debug
+//#define pr_debug printk
/*
* USB Host1 HS port
*/
@@ -70,25 +71,67 @@ static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable)
{
if (enable)
USBCTRL |= UCTRL_H1WIE;
- else
+ else {
USBCTRL &= ~UCTRL_H1WIE;
+ /* The interrupt must be disabled for at least 3
+ * cycles of the standby clock(32k Hz) , that is 0.094 ms*/
+ udelay(100);
+ }
+}
+
+static void _phy_lowpower_suspend(bool enable)
+{
+ if (enable) {
+ UH1_PORTSC1 |= PORTSC_PHCD;
+ }else {
+ UH1_PORTSC1 &= ~PORTSC_PHCD;
+ }
}
static void usbotg_clock_gate(bool on)
{
- struct clk *usboh3_clk = clk_get(NULL, "usboh3_clk");
- struct clk *usb_ahb_clk = clk_get(NULL, "usb_ahb_clk");
+ struct clk *usb_clk;
+ if (cpu_is_mx50()) {
+ if (on) {
+ usb_clk = clk_get(NULL, "usb_ahb_clk");
+ clk_enable(usb_clk);
+ clk_put(usb_clk);
+
+ } else {
+ usb_clk = clk_get(NULL, "usb_ahb_clk");
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
+ }
+ return;
+ }
+ if (cpu_is_mx53()) {
+ usb_clk = clk_get(NULL, "usb_phy2_clk");
+ if (on) {
+ clk_enable(usb_clk);
+ } else {
+ clk_disable(usb_clk);
+ }
+ clk_put(usb_clk);
+ }
if (on) {
- clk_enable(usb_ahb_clk);
- clk_enable(usboh3_clk);
+ usb_clk = clk_get(NULL, "usb_ahb_clk");
+ clk_enable(usb_clk);
+ clk_put(usb_clk);
+
+ usb_clk = clk_get(NULL, "usboh3_clk");
+ clk_enable(usb_clk);
+ clk_put(usb_clk);
+
} else {
- clk_disable(usboh3_clk);
- clk_disable(usb_ahb_clk);
- }
+ usb_clk = clk_get(NULL, "usboh3_clk");
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
- clk_put(usboh3_clk);
- clk_put(usb_ahb_clk);
+ usb_clk = clk_get(NULL, "usb_ahb_clk");
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
+ }
}
static int fsl_usb_host_init_ext(struct platform_device *pdev)
@@ -109,6 +152,10 @@ static int fsl_usb_host_init_ext(struct platform_device *pdev)
usb_clk = clk_get(NULL, "usb_utmi_clk");
clk_disable(usb_clk);
clk_put(usb_clk);
+ } else if (cpu_is_mx50()) {
+ usb_clk = clk_get(NULL, "usb_phy2_clk");
+ clk_enable(usb_clk);
+ clk_put(usb_clk);
}
ret = fsl_usb_host_init(pdev);
@@ -143,7 +190,12 @@ static void fsl_usb_host_uninit_ext(struct fsl_usb2_platform_data *pdata)
usb_clk = clk_get(&pdata->pdev->dev, "usb_phy2_clk");
clk_disable(usb_clk);
clk_put(usb_clk);
+ } else if (cpu_is_mx50()) {
+ usb_clk = clk_get(NULL, "usb_phy2_clk");
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
}
+
fsl_usb_host_uninit(pdata);
}
@@ -156,9 +208,14 @@ static struct fsl_usb2_platform_data usbh1_config = {
.power_budget = 500, /* 500 mA max power */
.wake_up_enable = _wake_up_enable,
.usb_clock_for_pm = usbotg_clock_gate,
+ .phy_lowpower_suspend = _phy_lowpower_suspend,
.transceiver = "utmi",
};
+void mx5_set_host1_vbus_func(driver_vbus_func driver_vbus)
+{
+ usbh1_config.platform_driver_vbus = driver_vbus;
+}
void __init mx5_usbh1_init(void)
{
if (cpu_is_mx51()) {
diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c
index 911908164efb..d2b51a1357c1 100644
--- a/arch/arm/plat-mxc/clock.c
+++ b/arch/arm/plat-mxc/clock.c
@@ -4,7 +4,7 @@
* Copyright (C) 2004 - 2005 Nokia corporation
* Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
* Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
- * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
* Copyright 2008 Juergen Beisert, kernel@pengutronix.de
*
* This program is free software; you can redistribute it and/or
@@ -173,14 +173,8 @@ int clk_enable(struct clk *clk)
if (clk == NULL || IS_ERR(clk))
return -EINVAL;
- spin_lock_irqsave(&clockfw_lock, flags);
-
- ret = __clk_enable(clk);
-
- spin_unlock_irqrestore(&clockfw_lock, flags);
-
if ((clk->flags & CPU_FREQ_TRIG_UPDATE)
- && (clk_get_usecount(clk) == 1)) {
+ && (clk_get_usecount(clk) == 0)) {
#if (defined(CONFIG_ARCH_MX5) || defined(CONFIG_ARCH_MX37))
if (low_freq_bus_used() && !low_bus_freq_mode)
set_low_bus_freq();
@@ -200,6 +194,13 @@ int clk_enable(struct clk *clk)
#endif
}
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+
+ ret = __clk_enable(clk);
+
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+
return ret;
}
EXPORT_SYMBOL(clk_enable);
@@ -228,12 +229,12 @@ void clk_disable(struct clk *clk)
set_low_bus_freq();
else {
if (!high_bus_freq_mode) {
- /* Currently at ow or medium set point,
+ /* Currently at low or medium set point,
* need to set to high setpoint
*/
set_high_bus_freq(0);
} else if (high_bus_freq_mode || low_bus_freq_mode) {
- /* Currently at ow or high set point,
+ /* Currently at low or high set point,
* need to set to medium setpoint
*/
set_high_bus_freq(0);
diff --git a/arch/arm/plat-mxc/dptc.c b/arch/arm/plat-mxc/dptc.c
index 6b7f5599909e..a26fd9b8d516 100644
--- a/arch/arm/plat-mxc/dptc.c
+++ b/arch/arm/plat-mxc/dptc.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -67,6 +67,7 @@ enum {
struct device *dev_data0;
struct device *dev_data1;
+struct dptc_device *dptc_device_data;
/*!
* In case the MXC device has multiple DPTC modules, this structure is used to
@@ -89,6 +90,8 @@ struct dptc_device {
int curr_wp;
/* DPTC vai bits */
u32 ptvai;
+ /* The base address of the DPTC */
+ void __iomem *membase;
/* The interrupt number used by the DPTC device */
int irq;
/* DPTC platform data pointer */
@@ -104,13 +107,13 @@ static void update_dptc_wp(struct dptc_device *drv_data, u32 wp)
voltage_uV = dptc_data->dptc_wp_allfreq[wp].voltage * 1000;
__raw_writel(dptc_data->dptc_wp_allfreq[wp].dcvr0,
- dptc_data->dcvr0_reg_addr);
+ drv_data->membase + dptc_data->dcvr0_reg_addr);
__raw_writel(dptc_data->dptc_wp_allfreq[wp].dcvr1,
- dptc_data->dcvr0_reg_addr + 0x4);
+ drv_data->membase + dptc_data->dcvr0_reg_addr + 0x4);
__raw_writel(dptc_data->dptc_wp_allfreq[wp].dcvr2,
- dptc_data->dcvr0_reg_addr + 0x8);
+ drv_data->membase + dptc_data->dcvr0_reg_addr + 0x8);
__raw_writel(dptc_data->dptc_wp_allfreq[wp].dcvr3,
- dptc_data->dcvr0_reg_addr + 0xC);
+ drv_data->membase + dptc_data->dcvr0_reg_addr + 0xC);
/* Set the voltage */
ret = regulator_set_voltage(drv_data->dptc_reg, voltage_uV, voltage_uV);
@@ -130,7 +133,8 @@ static irqreturn_t dptc_irq(int irq, void *dev_id)
struct device *dev = dev_id;
struct dptc_device *drv_data = dev->driver_data;
struct mxc_dptc_data *dptc_data = dev->platform_data;
- u32 dptccr = __raw_readl(dptc_data->dptccr_reg_addr);
+ u32 dptccr = __raw_readl(drv_data->membase
+ + dptc_data->dptccr_reg_addr);
u32 gpc_cntr = __raw_readl(dptc_data->gpc_cntr_reg_addr);
gpc_cntr = (gpc_cntr & dptc_data->dptccr);
@@ -145,7 +149,8 @@ static irqreturn_t dptc_irq(int irq, void *dev_id)
dptccr = (dptccr & ~(dptc_data->dptc_enable_bit)) |
(dptc_data->irq_mask);
dptccr = (dptccr & ~(dptc_data->dptc_nvcr_bit));
- __raw_writel(dptccr, dptc_data->dptccr_reg_addr);
+ __raw_writel(dptccr, drv_data->membase
+ + dptc_data->dptccr_reg_addr);
if (drv_data->turbo_mode_active == 1)
schedule_delayed_work(&drv_data->dptc_work, 0);
@@ -162,7 +167,8 @@ static void dptc_workqueue_handler(struct work_struct *work1)
struct dptc_device *drv_data =
container_of(dptc_work_tmp, struct dptc_device, dptc_work);
struct mxc_dptc_data *dptc_data = drv_data->dptc_platform_data;
- u32 dptccr = __raw_readl(dptc_data->dptccr_reg_addr);
+ u32 dptccr = __raw_readl(drv_data->membase
+ + dptc_data->dptccr_reg_addr);
switch (drv_data->ptvai) {
case DPTC_PTVAI_DECREASE:
@@ -193,7 +199,7 @@ static void dptc_workqueue_handler(struct work_struct *work1)
/* Enable DPTC and unmask its interrupt */
dptccr = (dptccr & ~(dptc_data->irq_mask)) |
dptc_data->dptc_nvcr_bit | dptc_data->dptc_enable_bit;
- __raw_writel(dptccr, dptc_data->dptccr_reg_addr);
+ __raw_writel(dptccr, drv_data->membase + dptc_data->dptccr_reg_addr);
}
/* Start DPTC unconditionally */
@@ -228,12 +234,12 @@ static int start_dptc(struct device *dev)
dptc_data->gpc_cntr_reg_addr);
}
- dptccr = __raw_readl(dptc_data->dptccr_reg_addr);
+ dptccr = __raw_readl(drv_data->membase + dptc_data->dptccr_reg_addr);
/* Enable DPTC and unmask its interrupt */
dptccr = ((dptccr & ~(dptc_data->irq_mask)) | dptc_data->enable_config);
- __raw_writel(dptccr, dptc_data->dptccr_reg_addr);
+ __raw_writel(dptccr, drv_data->membase + dptc_data->dptccr_reg_addr);
spin_unlock_irqrestore(&drv_data->lock, flags);
@@ -257,13 +263,13 @@ static void stop_dptc(struct device *dev)
struct dptc_device *drv_data = dev->driver_data;
u32 dptccr;
- dptccr = __raw_readl(dptc_data->dptccr_reg_addr);
+ dptccr = __raw_readl(drv_data->membase + dptc_data->dptccr_reg_addr);
/* disable DPTC and mask its interrupt */
dptccr = ((dptccr & ~(dptc_data->dptc_enable_bit)) |
dptc_data->irq_mask) & (~dptc_data->dptc_nvcr_bit);
- __raw_writel(dptccr, dptc_data->dptccr_reg_addr);
+ __raw_writel(dptccr, drv_data->membase + dptc_data->dptccr_reg_addr);
/* Restore Turbo Mode voltage to highest wp */
update_dptc_wp(drv_data, 0);
@@ -304,12 +310,12 @@ void dptc_suspend(int id)
if (!drv_data->dptc_is_active)
return;
- dptccr = __raw_readl(dptc_data->dptccr_reg_addr);
+ dptccr = __raw_readl(drv_data->membase + dptc_data->dptccr_reg_addr);
/* Disable DPTC and mask its interrupt */
dptccr = (dptccr & ~(dptc_data->dptc_enable_bit)) | dptc_data->irq_mask;
- __raw_writel(dptccr, dptc_data->dptccr_reg_addr);
+ __raw_writel(dptccr, drv_data->membase + dptc_data->dptccr_reg_addr);
}
EXPORT_SYMBOL(dptc_suspend);
@@ -344,20 +350,20 @@ void dptc_resume(int id)
return;
__raw_writel(dptc_data->dptc_wp_allfreq[0].dcvr0,
- dptc_data->dcvr0_reg_addr);
+ drv_data->membase + dptc_data->dcvr0_reg_addr);
__raw_writel(dptc_data->dptc_wp_allfreq[0].dcvr1,
- dptc_data->dcvr0_reg_addr + 0x4);
+ drv_data->membase + dptc_data->dcvr0_reg_addr + 0x4);
__raw_writel(dptc_data->dptc_wp_allfreq[0].dcvr2,
- dptc_data->dcvr0_reg_addr + 0x8);
+ drv_data->membase + dptc_data->dcvr0_reg_addr + 0x8);
__raw_writel(dptc_data->dptc_wp_allfreq[0].dcvr3,
- dptc_data->dcvr0_reg_addr + 0xC);
+ drv_data->membase + dptc_data->dcvr0_reg_addr + 0xC);
- dptccr = __raw_readl(dptc_data->dptccr_reg_addr);
+ dptccr = __raw_readl(drv_data->membase + dptc_data->dptccr_reg_addr);
/* Enable DPTC and unmask its interrupt */
dptccr = (dptccr & ~(dptc_data->irq_mask)) | dptc_data->dptc_enable_bit;
- __raw_writel(dptccr, dptc_data->dptccr_reg_addr);
+ __raw_writel(dptccr, drv_data->membase + dptc_data->dptccr_reg_addr);
}
EXPORT_SYMBOL(dptc_resume);
@@ -426,7 +432,6 @@ static DEVICE_ATTR(enable, 0644, dptc_show, dptc_store);
*/
static int __devinit mxc_dptc_probe(struct platform_device *pdev)
{
- struct dptc_device *dptc_device_data;
int ret = 0;
struct resource *res;
u32 dptccr = 0;
@@ -449,13 +454,16 @@ static int __devinit mxc_dptc_probe(struct platform_device *pdev)
goto err1;
}
+ dptc_device_data->membase = ioremap(res->start,
+ res->end - res->start + 1);
+
/*
* Request the DPTC interrupt
*/
dptc_device_data->irq = platform_get_irq(pdev, 0);
if (dptc_device_data->irq < 0) {
ret = dptc_device_data->irq;
- goto err1;
+ goto err2;
}
ret =
@@ -463,7 +471,7 @@ static int __devinit mxc_dptc_probe(struct platform_device *pdev)
pdev->name, &pdev->dev);
if (ret) {
printk(KERN_ERR "DPTC: Unable to attach to DPTC interrupt\n");
- goto err1;
+ goto err2;
}
dptc_device_data->curr_wp = 0;
@@ -471,7 +479,8 @@ static int __devinit mxc_dptc_probe(struct platform_device *pdev)
dptc_device_data->turbo_mode_active = 0;
dptc_device_data->ptvai = 0;
- dptccr = __raw_readl(dptc_data->dptccr_reg_addr);
+ dptccr = __raw_readl(dptc_device_data->membase
+ + dptc_data->dptccr_reg_addr);
printk(KERN_INFO "DPTC mxc_dptc_probe()\n");
@@ -487,32 +496,33 @@ static int __devinit mxc_dptc_probe(struct platform_device *pdev)
else
printk(KERN_ERR "DPTC: Pointer to DPTC table is NULL\
not started\n");
- goto err1;
+ goto err3;
}
dptc_device_data->dptc_reg = regulator_get(NULL, dptc_data->reg_id);
if (IS_ERR(dptc_device_data->dptc_reg)) {
clk_put(dptc_device_data->dptc_clk);
printk(KERN_ERR "%s: failed to get regulator\n", __func__);
- goto err1;
+ goto err3;
}
INIT_DELAYED_WORK(&dptc_device_data->dptc_work, dptc_workqueue_handler);
/* Enable Reference Circuits */
dptccr = (dptccr & ~(dptc_data->dcr_mask)) | dptc_data->init_config;
- __raw_writel(dptccr, dptc_data->dptccr_reg_addr);
+ __raw_writel(dptccr, dptc_device_data->membase
+ + dptc_data->dptccr_reg_addr);
ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_enable.attr);
if (ret) {
printk(KERN_ERR
"DPTC: Unable to register sysdev entry for dptc");
- goto err1;
+ goto err3;
}
if (ret != 0) {
printk(KERN_ERR "DPTC: Unable to start");
- goto err1;
+ goto err3;
}
dptc_device_data->dptc_clk = clk_get(NULL, dptc_data->clk_id);
@@ -529,6 +539,10 @@ static int __devinit mxc_dptc_probe(struct platform_device *pdev)
return 0;
+err3:
+ free_irq(dptc_device_data->irq, &pdev->dev);
+err2:
+ iounmap(dptc_device_data->membase);
err1:
dev_err(&pdev->dev, "Failed to probe DPTC\n");
kfree(dptc_device_data);
@@ -607,6 +621,10 @@ static int __init dptc_init(void)
static void __exit dptc_cleanup(void)
{
+ free_irq(dptc_device_data->irq, NULL);
+ iounmap(dptc_device_data->membase);
+ kfree(dptc_device_data);
+
/* Unregister the device structure */
platform_driver_unregister(&mxc_dptc_driver);
diff --git a/arch/arm/plat-mxc/dvfs_core.c b/arch/arm/plat-mxc/dvfs_core.c
index 43d0a3a8adeb..143bc07834ed 100644
--- a/arch/arm/plat-mxc/dvfs_core.c
+++ b/arch/arm/plat-mxc/dvfs_core.c
@@ -135,18 +135,19 @@ static void dvfs_load_config(int set_point)
reg |= dvfs_core_setpoint[set_point].downthr <<
MXC_DVFSTHRS_DNTHR_OFFSET;
reg |= dvfs_core_setpoint[set_point].panicthr;
- __raw_writel(reg, dvfs_data->dvfs_thrs_reg_addr);
+ __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_THRS);
reg = 0;
reg |= dvfs_core_setpoint[set_point].downcnt <<
MXC_DVFSCOUN_DNCNT_OFFSET;
reg |= dvfs_core_setpoint[set_point].upcnt << MXC_DVFSCOUN_UPCNT_OFFSET;
- __raw_writel(reg, dvfs_data->dvfs_coun_reg_addr);
+ __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_COUN);
/* Set EMAC value */
__raw_writel((dvfs_core_setpoint[set_point].emac <<
MXC_DVFSEMAC_EMAC_OFFSET),
- dvfs_data->dvfs_emac_reg_addr);
+ dvfs_data->membase
+ + MXC_DVFSCORE_EMAC);
}
@@ -187,14 +188,14 @@ static int set_cpu_freq(int wp)
}
spin_lock_irqsave(&mxc_dvfs_core_lock, flags);
/* PLL_RELOCK, set ARM_FREQ_SHIFT_DIVIDER */
- reg = __raw_readl(dvfs_data->ccm_cdcr_reg_addr);
+ reg = __raw_readl(ccm_base + dvfs_data->ccm_cdcr_offset);
reg &= 0xFFFFFFFB;
- __raw_writel(reg, dvfs_data->ccm_cdcr_reg_addr);
+ __raw_writel(reg, ccm_base + dvfs_data->ccm_cdcr_offset);
setup_pll();
/* START the GPC main control FSM */
/* set VINC */
- reg = __raw_readl(dvfs_data->gpc_vcr_reg_addr);
+ reg = __raw_readl(gpc_base + dvfs_data->gpc_vcr_offset);
reg &= ~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK |
MXC_GPCVCR_VCNT_MASK);
@@ -202,18 +203,19 @@ static int set_cpu_freq(int wp)
reg |= 1 << MXC_GPCVCR_VINC_OFFSET;
reg |= (1 << MXC_GPCVCR_VCNTU_OFFSET) |
- (1 << MXC_GPCVCR_VCNT_OFFSET);
- __raw_writel(reg, dvfs_data->gpc_vcr_reg_addr);
+ (1 << MXC_GPCVCR_VCNT_OFFSET);
+ __raw_writel(reg, gpc_base + dvfs_data->gpc_vcr_offset);
- reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr);
+ reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset);
reg &= ~(MXC_GPCCNTR_ADU_MASK | MXC_GPCCNTR_FUPD_MASK);
reg |= MXC_GPCCNTR_FUPD;
reg |= MXC_GPCCNTR_ADU;
- __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr);
+ __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset);
reg |= MXC_GPCCNTR_STRT;
- __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr);
- while (__raw_readl(dvfs_data->gpc_cntr_reg_addr) & 0x4000)
+ __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset);
+ while (__raw_readl(gpc_base + dvfs_data->gpc_cntr_offset)
+ & 0x4000)
udelay(10);
spin_unlock_irqrestore(&mxc_dvfs_core_lock, flags);
@@ -234,13 +236,13 @@ static int set_cpu_freq(int wp)
/* Change arm_podf only */
/* set ARM_FREQ_SHIFT_DIVIDER */
- reg = __raw_readl(dvfs_data->ccm_cdcr_reg_addr);
+ reg = __raw_readl(ccm_base + dvfs_data->ccm_cdcr_offset);
reg &= 0xFFFFFFFB;
reg |= 1 << 2;
- __raw_writel(reg, dvfs_data->ccm_cdcr_reg_addr);
+ __raw_writel(reg, ccm_base + dvfs_data->ccm_cdcr_offset);
/* Get ARM_PODF */
- reg = __raw_readl(dvfs_data->ccm_cacrr_reg_addr);
+ reg = __raw_readl(ccm_base + dvfs_data->ccm_cacrr_offset);
arm_podf = reg & 0x07;
if (podf == arm_podf) {
printk(KERN_DEBUG
@@ -268,37 +270,38 @@ static int set_cpu_freq(int wp)
reg &= 0xFFFFFFF8;
reg |= arm_podf;
- reg1 = __raw_readl(dvfs_data->ccm_cdhipr_reg_addr);
+ reg1 = __raw_readl(ccm_base + dvfs_data->ccm_cdhipr_offset);
if ((reg1 & 0x00010000) == 0)
- __raw_writel(reg, dvfs_data->ccm_cacrr_reg_addr);
+ __raw_writel(reg,
+ ccm_base + dvfs_data->ccm_cacrr_offset);
else {
printk(KERN_DEBUG "ARM_PODF still in busy!!!!\n");
return 0;
}
/* START the GPC main control FSM */
- reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr);
+ reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset);
reg |= MXC_GPCCNTR_FUPD;
/* ADU=1, select ARM domain */
reg |= MXC_GPCCNTR_ADU;
- __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr);
+ __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset);
/* set VINC */
- reg = __raw_readl(dvfs_data->gpc_vcr_reg_addr);
+ reg = __raw_readl(gpc_base + dvfs_data->gpc_vcr_offset);
reg &=
~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK |
MXC_GPCVCR_VCNT_MASK);
reg |= (1 << MXC_GPCVCR_VCNTU_OFFSET) |
(100 << MXC_GPCVCR_VCNT_OFFSET) |
(vinc << MXC_GPCVCR_VINC_OFFSET);
- __raw_writel(reg, dvfs_data->gpc_vcr_reg_addr);
+ __raw_writel(reg, gpc_base + dvfs_data->gpc_vcr_offset);
- reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr);
+ reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset);
reg &= (~(MXC_GPCCNTR_ADU | MXC_GPCCNTR_FUPD));
reg |= MXC_GPCCNTR_ADU | MXC_GPCCNTR_FUPD | MXC_GPCCNTR_STRT;
- __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr);
+ __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset);
/* Wait for arm podf Enable */
- while ((__raw_readl(dvfs_data->gpc_cntr_reg_addr) &
+ while ((__raw_readl(gpc_base + dvfs_data->gpc_cntr_offset) &
MXC_GPCCNTR_STRT) == MXC_GPCCNTR_STRT) {
printk(KERN_DEBUG "Waiting arm_podf enabled!\n");
udelay(10);
@@ -317,9 +320,9 @@ static int set_cpu_freq(int wp)
propagate_rate(pll1_sw_clk);
/* Clear the ARM_FREQ_SHIFT_DIVIDER */
- reg = __raw_readl(dvfs_data->ccm_cdcr_reg_addr);
+ reg = __raw_readl(ccm_base + dvfs_data->ccm_cdcr_offset);
reg &= 0xFFFFFFFB;
- __raw_writel(reg, dvfs_data->ccm_cdcr_reg_addr);
+ __raw_writel(reg, ccm_base + dvfs_data->ccm_cdcr_offset);
}
#if defined(CONFIG_CPU_FREQ_IMX)
cpufreq_trig_needed = 1;
@@ -344,23 +347,23 @@ static int start_dvfs(void)
dvfs_load_config(0);
/* config reg GPC_CNTR */
- reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr);
+ reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset);
reg &= ~MXC_GPCCNTR_GPCIRQM;
/* GPCIRQ=1, select ARM IRQ */
reg |= MXC_GPCCNTR_GPCIRQ_ARM;
/* ADU=1, select ARM domain */
reg |= MXC_GPCCNTR_ADU;
- __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr);
+ __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset);
/* Set PREDIV bits */
- reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr);
+ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR);
reg = (reg & ~(dvfs_data->prediv_mask));
reg |= (dvfs_data->prediv_val) << (dvfs_data->prediv_offset);
- __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr);
+ __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR);
/* Enable DVFS interrupt */
- reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr);
+ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR);
/* FSVAIM=0 */
reg = (reg & ~MXC_DVFSCNTR_FSVAIM);
/* Set MAXF, MINF */
@@ -376,12 +379,12 @@ static int start_dvfs(void)
/* Set DIV3CK */
reg = (reg & ~(dvfs_data->div3ck_mask));
reg |= (dvfs_data->div3ck_val) << (dvfs_data->div3ck_offset);
- __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr);
+ __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR);
/* Enable DVFS */
- reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr);
+ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR);
reg |= MXC_DVFSCNTR_DVFEN;
- __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr);
+ __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR);
dvfs_core_is_active = 1;
@@ -416,20 +419,20 @@ static irqreturn_t dvfs_irq(int irq, void *dev_id)
u32 reg;
/* Check if DVFS0 (ARM) id requesting for freqency/voltage update */
- if ((__raw_readl(dvfs_data->gpc_cntr_reg_addr) & MXC_GPCCNTR_DVFS0CR) ==
- 0)
+ if ((__raw_readl(gpc_base + dvfs_data->gpc_cntr_offset)
+ & MXC_GPCCNTR_DVFS0CR) == 0)
return IRQ_NONE;
/* Mask DVFS irq */
- reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr);
+ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR);
/* FSVAIM=1 */
reg |= MXC_DVFSCNTR_FSVAIM;
- __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr);
+ __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR);
/* Mask GPC1 irq */
- reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr);
+ reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset);
reg |= MXC_GPCCNTR_GPCIRQM | 0x1000000;
- __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr);
+ __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset);
schedule_delayed_work(&dvfs_core_handler, 0);
return IRQ_HANDLED;
@@ -448,7 +451,7 @@ static void dvfs_core_work_handler(struct work_struct *work)
low_freq_bus_ready = low_freq_bus_used();
/* Check DVFS frequency adjustment interrupt status */
- reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr);
+ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR);
fsvai = (reg & MXC_DVFSCNTR_FSVAI_MASK) >> MXC_DVFSCNTR_FSVAI_OFFSET;
/* Check FSVAI, FSVAI=0 is error */
if (fsvai == FSVAI_FREQ_NOCHANGE) {
@@ -520,7 +523,7 @@ static void dvfs_core_work_handler(struct work_struct *work)
END: /* Set MAXF, MINF */
- reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr);
+ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR);
reg = (reg & ~(MXC_DVFSCNTR_MAXF_MASK | MXC_DVFSCNTR_MINF_MASK));
reg |= maxf << MXC_DVFSCNTR_MAXF_OFFSET;
reg |= minf << MXC_DVFSCNTR_MINF_OFFSET;
@@ -532,11 +535,11 @@ END: /* Set MAXF, MINF */
/* LBFL=1 */
reg = (reg & ~MXC_DVFSCNTR_LBFL);
reg |= MXC_DVFSCNTR_LBFL;
- __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr);
+ __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR);
/*Unmask GPC1 IRQ */
- reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr);
+ reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset);
reg &= ~MXC_GPCCNTR_GPCIRQM;
- __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr);
+ __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset);
#if defined(CONFIG_CPU_FREQ_IMX)
if (cpufreq_trig_needed == 1) {
@@ -559,10 +562,12 @@ static void stop_dvfs(void)
if (dvfs_core_is_active) {
/* Mask dvfs irq, disable DVFS */
- reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr);
+ reg = __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_CNTR);
/* FSVAIM=1 */
reg |= MXC_DVFSCNTR_FSVAIM;
- __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr);
+ __raw_writel(reg, dvfs_data->membase
+ + MXC_DVFSCORE_CNTR);
curr_wp = 0;
if (!high_bus_freq_mode)
@@ -580,9 +585,11 @@ static void stop_dvfs(void)
}
spin_lock_irqsave(&mxc_dvfs_core_lock, flags);
- reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr);
+ reg = __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_CNTR);
reg = (reg & ~MXC_DVFSCNTR_DVFEN);
- __raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr);
+ __raw_writel(reg, dvfs_data->membase
+ + MXC_DVFSCORE_CNTR);
spin_unlock_irqrestore(&mxc_dvfs_core_lock, flags);
@@ -610,39 +617,56 @@ void dump_dvfs_core_regs()
printk(KERN_DEBUG "diff = %d\n", diff);
printk(KERN_INFO "THRS = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS));
printk(KERN_INFO "COUNT = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x04));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x04));
printk(KERN_INFO "SIG1 = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x08));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x08));
printk(KERN_INFO "SIG0 = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x0c));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x0c));
printk(KERN_INFO "GPC0 = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x10));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x10));
printk(KERN_INFO "GPC1 = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x14));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x14));
printk(KERN_INFO "GPBT = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x18));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x18));
printk(KERN_INFO "EMAC = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x1c));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x1c));
printk(KERN_INFO "CNTR = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x20));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x20));
printk(KERN_INFO "LTR0_0 = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x24));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x24));
printk(KERN_INFO "LTR0_1 = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x28));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x28));
printk(KERN_INFO "LTR1_0 = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x2c));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x2c));
printk(KERN_DEBUG "LTR1_1 = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x30));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x30));
printk(KERN_INFO "PT0 = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x34));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x34));
printk(KERN_INFO "PT1 = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x38));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x38));
printk(KERN_INFO "PT2 = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x3c));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x3c));
printk(KERN_INFO "PT3 = 0x%08x\n",
- __raw_readl(dvfs_data->dvfs_thrs_reg_addr+0x40));
+ __raw_readl(dvfs_data->membase
+ + MXC_DVFSCORE_THRS + 0x40));
}
static ssize_t downthreshold_show(struct device *dev,
@@ -741,7 +765,6 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev)
{
int err = 0;
struct resource *res;
- int irq;
printk(KERN_INFO "mxc_dvfs_core_probe\n");
dvfs_dev = &pdev->dev;
@@ -780,22 +803,25 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev)
err = -ENODEV;
goto err1;
}
-
+ dvfs_data->membase = ioremap(res->start, res->end - res->start + 1);
/*
* Request the DVFS interrupt
*/
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- err = irq;
- goto err1;
+ dvfs_data->irq = platform_get_irq(pdev, 0);
+ if (dvfs_data->irq < 0) {
+ err = dvfs_data->irq;
+ goto err2;
}
/* request the DVFS interrupt */
- err = request_irq(irq, dvfs_irq, IRQF_SHARED, "dvfs", dvfs_dev);
- if (err)
+ err = request_irq(dvfs_data->irq, dvfs_irq, IRQF_SHARED, "dvfs",
+ dvfs_dev);
+ if (err) {
printk(KERN_ERR
"DVFS: Unable to attach to DVFS interrupt,err = %d",
err);
+ goto err2;
+ }
clk_enable(dvfs_clk);
err = init_dvfs_controller();
@@ -809,14 +835,14 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev)
if (err) {
printk(KERN_ERR
"DVFS: Unable to register sysdev entry for DVFS");
- return err;
+ goto err3;
}
err = sysfs_create_file(&dvfs_dev->kobj, &dev_attr_show_regs.attr);
if (err) {
printk(KERN_ERR
"DVFS: Unable to register sysdev entry for DVFS");
- return err;
+ goto err3;
}
@@ -824,14 +850,14 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev)
if (err) {
printk(KERN_ERR
"DVFS: Unable to register sysdev entry for DVFS");
- return err;
+ goto err3;
}
err = sysfs_create_file(&dvfs_dev->kobj, &dev_attr_down_count.attr);
if (err) {
printk(KERN_ERR
"DVFS: Unable to register sysdev entry for DVFS");
- return err;
+ goto err3;
}
/* Set the current working point. */
@@ -844,7 +870,10 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev)
#endif
return err;
-
+err3:
+ free_irq(dvfs_data->irq, dvfs_dev);
+err2:
+ iounmap(dvfs_data->membase);
err1:
dev_err(&pdev->dev, "Failed to probe DVFS CORE\n");
return err;
@@ -914,13 +943,15 @@ static void __exit dvfs_cleanup(void)
stop_dvfs();
/* release the DVFS interrupt */
- free_irq(MXC_INT_GPC1, NULL);
+ free_irq(dvfs_data->irq, dvfs_dev);
sysfs_remove_file(&dvfs_dev->kobj, &dev_attr_enable.attr);
/* Unregister the device structure */
platform_driver_unregister(&mxc_dvfs_core_driver);
+ iounmap(ccm_base);
+ iounmap(dvfs_data->membase);
clk_put(cpu_clk);
clk_put(dvfs_clk);
diff --git a/arch/arm/plat-mxc/dvfs_per.c b/arch/arm/plat-mxc/dvfs_per.c
index 43d0dfccff50..e57f8a2fefcd 100644
--- a/arch/arm/plat-mxc/dvfs_per.c
+++ b/arch/arm/plat-mxc/dvfs_per.c
@@ -51,15 +51,14 @@
#endif
/* DVFS PER */
-static void __iomem *dvfs_per_base;
-#define MXC_DVFS_PER_LTR0 (dvfs_per_base)
-#define MXC_DVFS_PER_LTR1 (dvfs_per_base + 0x04)
-#define MXC_DVFS_PER_LTR2 (dvfs_per_base + 0x08)
-#define MXC_DVFS_PER_LTR3 (dvfs_per_base + 0x0C)
-#define MXC_DVFS_PER_LTBR0 (dvfs_per_base + 0x10)
-#define MXC_DVFS_PER_LTBR1 (dvfs_per_base + 0x14)
-#define MXC_DVFS_PER_PMCR0 (dvfs_per_base + 0x18)
-#define MXC_DVFS_PER_PMCR1 (dvfs_per_base + 0x1C)
+#define MXC_DVFS_PER_LTR0 0x00
+#define MXC_DVFS_PER_LTR1 0x04
+#define MXC_DVFS_PER_LTR2 0x08
+#define MXC_DVFS_PER_LTR3 0x0C
+#define MXC_DVFS_PER_LTBR0 0x10
+#define MXC_DVFS_PER_LTBR1 0x14
+#define MXC_DVFS_PER_PMCR0 0x18
+#define MXC_DVFS_PER_PMCR1 0x1C
#define DRIVER_NAME "DVFSPER"
#define DVFS_PER_DEBUG 0
@@ -134,16 +133,16 @@ static void dvfs_per_load_config(void)
{
u32 reg;
- reg = __raw_readl(MXC_DVFS_PER_LTR0);
+ reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR0);
reg &= ~MXC_DVFSLTR0_UPTHR_MASK;
reg &= ~MXC_DVFSLTR0_DNTHR_MASK;
reg |= dvfs_per_setpoint[cur_setpoint].upthr <<
MXC_DVFSLTR0_UPTHR_OFFSET;
reg |= dvfs_per_setpoint[cur_setpoint].downthr <<
MXC_DVFSLTR0_DNTHR_OFFSET;
- __raw_writel(reg, MXC_DVFS_PER_LTR0);
+ __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR0);
- reg = __raw_readl(MXC_DVFS_PER_LTR1);
+ reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR1);
reg &= ~MXC_DVFSLTR1_PNCTHR_MASK;
reg &= ~MXC_DVFSLTR1_DNCNT_MASK;
reg &= ~MXC_DVFSLTR1_UPCNT_MASK;
@@ -153,11 +152,11 @@ static void dvfs_per_load_config(void)
MXC_DVFSLTR1_UPCNT_OFFSET;
reg |= dvfs_per_setpoint[cur_setpoint].panicthr <<
MXC_DVFSLTR1_PNCTHR_OFFSET;
- __raw_writel(reg, MXC_DVFS_PER_LTR1);
+ __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR1);
reg = dvfs_per_setpoint[cur_setpoint].emac <<
MXC_DVFSLTR2_EMAC_OFFSET;
- __raw_writel(reg, MXC_DVFS_PER_LTR2);
+ __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR2);
}
/*!
@@ -175,29 +174,29 @@ static int init_dvfs_per_controller(void)
{
u32 reg;
- reg = __raw_readl(MXC_DVFS_PER_LTR0);
+ reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR0);
/* DIV3CLK */
reg &= ~dvfsper_plt_data->div3_mask;
reg |= (dvfsper_plt_data->div3_div <<
dvfsper_plt_data->div3_offset);
- __raw_writel(reg, MXC_DVFS_PER_LTR0);
+ __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR0);
- reg = __raw_readl(MXC_DVFS_PER_LTR1);
+ reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR1);
/* Set load tracking buffer register source */
reg &= ~MXC_DVFSLTR1_LTBRSR;
reg |= MXC_DVFSLTR1_LTBRSR;
reg &= ~MXC_DVFSLTR1_LTBRSH;
- __raw_writel(reg, MXC_DVFS_PER_LTR1);
+ __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR1);
/* Enable all the peripheral signals, but VPU and IPU panic*/
- __raw_writel(0x30000, MXC_DVFS_PER_PMCR1);
+ __raw_writel(0x30000, dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR1);
/* Disable weighted load tracking signals */
- __raw_writel(0, MXC_DVFS_PER_LTR3);
+ __raw_writel(0, dvfsper_plt_data->membase + MXC_DVFS_PER_LTR3);
- reg = __raw_readl(MXC_DVFS_PER_PMCR0);
+ reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);
reg &= ~MXC_DVFSPMCR0_DVFEV;
reg |= MXC_DVFSPMCR0_LBMI;
- __raw_writel(reg, MXC_DVFS_PER_PMCR0);
+ __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);
/* DVFS loading config */
dvfs_per_load_config();
@@ -220,14 +219,22 @@ static void dump_dvfs_per_regs(void)
if (diff < 90000)
printk(KERN_INFO "diff = %d\n", diff);
- printk(KERN_INFO "LTRO = 0x%08x\n", __raw_readl(MXC_DVFS_PER_LTR0));
- printk(KERN_INFO "LTR1 = 0x%08x\n", __raw_readl(MXC_DVFS_PER_LTR1));
- printk(KERN_INFO "LTR2 = 0x%08x\n", __raw_readl(MXC_DVFS_PER_LTR2));
- printk(KERN_INFO "LTR3 = 0x%08x\n", __raw_readl(MXC_DVFS_PER_LTR3));
- printk(KERN_INFO "LBTR0 = 0x%08x\n", __raw_readl(MXC_DVFS_PER_LTBR0));
- printk(KERN_INFO "LBTR1 = 0x%08x\n", __raw_readl(MXC_DVFS_PER_LTBR1));
- printk(KERN_INFO "PMCR0 = 0x%08x\n", __raw_readl(MXC_DVFS_PER_PMCR0));
- printk(KERN_INFO "PMCR1 = 0x%08x\n", __raw_readl(MXC_DVFS_PER_PMCR1));
+ printk(KERN_INFO "LTRO = 0x%08x\n",
+ __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR0));
+ printk(KERN_INFO "LTR1 = 0x%08x\n",
+ __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR1));
+ printk(KERN_INFO "LTR2 = 0x%08x\n",
+ __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR2));
+ printk(KERN_INFO "LTR3 = 0x%08x\n",
+ __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTR3));
+ printk(KERN_INFO "LBTR0 = 0x%08x\n",
+ __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTBR0));
+ printk(KERN_INFO "LBTR1 = 0x%08x\n",
+ __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_LTBR1));
+ printk(KERN_INFO "PMCR0 = 0x%08x\n",
+ __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0));
+ printk(KERN_INFO "PMCR1 = 0x%08x\n",
+ __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR1));
}
#endif
@@ -240,21 +247,22 @@ static irqreturn_t dvfs_per_irq(int irq, void *dev_id)
MXC_GPCCNTR_DVFS1CR) == 0)
return IRQ_NONE;
/* Mask DVFS irq */
- reg = __raw_readl(MXC_DVFS_PER_PMCR0);
+ reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);
/* FSVAIM=1 */
reg |= MXC_DVFSPMCR0_FSVAIM;
- __raw_writel(reg, MXC_DVFS_PER_PMCR0);
+ __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);
/* Mask GPC1 irq */
reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr);
reg |= MXC_GPCCNTR_GPCIRQM | 0x1000000;
__raw_writel(reg, dvfsper_plt_data->gpc_cntr_reg_addr);
- reg = __raw_readl(MXC_DVFS_PER_PMCR0);
+ reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);
if (reg & MXC_DVFSPMCR0_LBFL) {
/* clear LBFL */
reg = (reg & ~MXC_DVFSPMCR0_LBFL);
reg |= MXC_DVFSPMCR0_LBFL;
- __raw_writel(reg, MXC_DVFS_PER_PMCR0);
+ __raw_writel(reg, dvfsper_plt_data->membase
+ + MXC_DVFS_PER_PMCR0);
}
schedule_delayed_work(&dvfs_per_work, 0);
return IRQ_HANDLED;
@@ -269,7 +277,7 @@ static void dvfs_per_handler(struct work_struct *work)
int retry = 20;
/* Check DVFS frequency adjustment interrupt status */
- reg = __raw_readl(MXC_DVFS_PER_PMCR0);
+ reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);
fsvai = (reg & MXC_DVFSPMCR0_FSVAI_MASK) >> MXC_DVFSPMCR0_FSVAI_OFFSET;
/* Check FSVAI, FSVAI=0 is error */
if (fsvai == FSVAI_FREQ_NOCHANGE) {
@@ -290,9 +298,11 @@ static void dvfs_per_handler(struct work_struct *work)
#ifndef DVFS_SW_WORKAROUND
spin_lock_irqsave(&mxc_dvfs_per_lock, flags);
- reg = __raw_readl(MXC_DVFS_PER_PMCR0);
+ reg = __raw_readl(dvfsper_plt_data->membase
+ + MXC_DVFS_PER_PMCR0);
reg &= ~MXC_DVFSPMCR0_UDCS;
- __raw_writel(reg, MXC_DVFS_PER_PMCR0);
+ __raw_writel(reg, dvfsper_plt_data->membase
+ + MXC_DVFS_PER_PMCR0);
/* Set the peripheral divider */
reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr);
@@ -367,9 +377,11 @@ static void dvfs_per_handler(struct work_struct *work)
#ifndef DVFS_SW_WORKAROUND
spin_lock_irqsave(&mxc_dvfs_per_lock, flags);
- reg = __raw_readl(MXC_DVFS_PER_PMCR0);
+ reg = __raw_readl(dvfsper_plt_data->membase
+ + MXC_DVFS_PER_PMCR0);
reg |= MXC_DVFSPMCR0_UDCS;
- __raw_writel(reg, MXC_DVFS_PER_PMCR0);
+ __raw_writel(reg, dvfsper_plt_data->membase
+ + MXC_DVFS_PER_PMCR0);
reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr);
reg &= ~(MXC_GPCCNTR_ADU_MASK | MXC_GPCCNTR_FUPD_MASK);
@@ -432,13 +444,15 @@ END:
dump_dvfs_per_regs(void)();
#endif
if (dvfs_per_is_active) {
- reg = __raw_readl(MXC_DVFS_PER_PMCR0);
+ reg = __raw_readl(dvfsper_plt_data->membase
+ + MXC_DVFS_PER_PMCR0);
/* Enable dVFS interrupt */
/* FSVAIM=0 */
reg &= ~MXC_DVFSPMCR0_FSVAI_MASK;
reg |= FSVAI_FREQ_NOCHANGE;
reg = (reg & ~MXC_DVFSPMCR0_FSVAIM);
- __raw_writel(reg, MXC_DVFS_PER_PMCR0);
+ __raw_writel(reg, dvfsper_plt_data->membase
+ + MXC_DVFS_PER_PMCR0);
/*Unmask GPC1 IRQ */
reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr);
reg &= ~MXC_GPCCNTR_GPCIRQM;
@@ -453,9 +467,9 @@ static void force_freq_change(void)
freq_increased = 0;
- reg = __raw_readl(MXC_DVFS_PER_PMCR0);
+ reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);
reg |= MXC_DVFSPMCR0_UDCS;
- __raw_writel(reg, MXC_DVFS_PER_PMCR0);
+ __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);
if (cpu_is_mx51()) {
/*Change the DDR freq to 133Mhz. */
@@ -513,7 +527,8 @@ static int start(void)
if (bus_freq_scaling_is_active) {
dvfs_per_is_paused = 1;
- printk(KERN_INFO "Cannot start DVFS-PER since bus_freq_scaling is active\n");
+ printk(KERN_INFO "Cannot start DVFS-PER since bus_freq_scaling\
+ is active\n");
return 0;
}
@@ -539,7 +554,7 @@ static int start(void)
reg &= ~MXC_GPCCNTR_ADU;
__raw_writel(reg, dvfsper_plt_data->gpc_cntr_reg_addr);
- reg = __raw_readl(MXC_DVFS_PER_PMCR0);
+ reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);
/* Select ARM domain */
reg |= MXC_DVFSPMCR0_DVFIS;
/* Set the UDCS bit */
@@ -550,7 +565,7 @@ static int start(void)
/*Set the FSVAI to no_freq_change */
reg &= ~MXC_DVFSPMCR0_FSVAI_MASK;
reg |= FSVAI_FREQ_NOCHANGE << MXC_DVFSPMCR0_FSVAI_OFFSET;
- __raw_writel(reg, MXC_DVFS_PER_PMCR0);
+ __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);
/* config reg GPC_CNTR */
reg = __raw_readl(dvfsper_plt_data->gpc_cntr_reg_addr);
@@ -560,9 +575,9 @@ static int start(void)
__raw_writel(reg, dvfsper_plt_data->gpc_cntr_reg_addr);
/* Enable DVFS */
- reg = __raw_readl(MXC_DVFS_PER_PMCR0);
+ reg = __raw_readl(dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);
reg |= MXC_DVFSPMCR0_DVFEN;
- __raw_writel(reg, MXC_DVFS_PER_PMCR0);
+ __raw_writel(reg, dvfsper_plt_data->membase + MXC_DVFS_PER_PMCR0);
dvfs_per_is_active = 1;
spin_unlock_irqrestore(&mxc_dvfs_per_lock, flags);
@@ -598,17 +613,21 @@ static void stop(void)
spin_lock_irqsave(&mxc_dvfs_per_lock, flags);
/* Mask dvfs irq, disable DVFS */
- reg = __raw_readl(MXC_DVFS_PER_PMCR0);
+ reg = __raw_readl(dvfsper_plt_data->membase
+ + MXC_DVFS_PER_PMCR0);
/* FSVAIM=1 */
reg |= MXC_DVFSPMCR0_FSVAIM;
- __raw_writel(reg, MXC_DVFS_PER_PMCR0);
+ __raw_writel(reg, dvfsper_plt_data->membase
+ + MXC_DVFS_PER_PMCR0);
if (cur_setpoint != 0)
force_freq_change();
- reg = __raw_readl(MXC_DVFS_PER_PMCR0);
+ reg = __raw_readl(dvfsper_plt_data->membase
+ + MXC_DVFS_PER_PMCR0);
reg = (reg & ~MXC_DVFSPMCR0_DVFEN);
- __raw_writel(reg, MXC_DVFS_PER_PMCR0);
+ __raw_writel(reg, dvfsper_plt_data->membase
+ + MXC_DVFS_PER_PMCR0);
spin_unlock_irqrestore(&mxc_dvfs_per_lock, flags);
clk_disable(dvfs_clk);
@@ -770,7 +789,8 @@ static int __devinit mxc_dvfsper_probe(struct platform_device *pdev)
ret = -ENODEV;
goto err1;
}
- dvfs_per_base = gpc_base + 0x1C4;
+ dvfsper_plt_data->membase = ioremap(res->start,
+ res->end - res->start + 1);
/*
* Request the DVFSPER interrupt
diff --git a/arch/arm/plat-mxc/include/mach/arc_otg.h b/arch/arm/plat-mxc/include/mach/arc_otg.h
index 1b2511079560..2a58492ccc70 100644
--- a/arch/arm/plat-mxc/include/mach/arc_otg.h
+++ b/arch/arm/plat-mxc/include/mach/arc_otg.h
@@ -147,6 +147,7 @@
#define USBCTRL_HOST3 USBOTHER_REG(0x18) /* USB Cotrol Register 1*/
#define USBH1_PHY_CTRL0 USBOTHER_REG(0x1c) /* USB Cotrol Register 1*/
#define USBH1_PHY_CTRL1 USBOTHER_REG(0x20) /* USB Cotrol Register 1*/
+#define USB_CLKONOFF_CTRL USBOTHER_REG(0x24) /* USB Clock on/off Control Register */
/*
* register bits
@@ -245,6 +246,7 @@
#define UCTRL_OBPVAL_RXDP (1 << 26) /* OTG RxDp status in bypass mode */
#define UCTRL_OBPVAL_RXDM (1 << 25) /* OTG RxDm status in bypass mode */
#define UCTRL_OPM (1 << 24) /* OTG power mask */
+#define UCTRL_O_PWR_POL (1 << 24) /* OTG power pin polarity */
#define UCTRL_H2WIR (1 << 23) /* HOST2 wakeup intr request received */
#define UCTRL_H2SIC_MASK (3 << 21) /* HOST2 Serial Interface Config: */
#define UCTRL_H2SIC_DU6 (0 << 21) /* Differential/unidirectional 6 wire */
@@ -329,6 +331,7 @@
#define USB_UTMI_PHYCTRL_OC_POL (1 << 9) /* OTG Polarity of Overcurrent */
#define USB_UTMI_PHYCTRL_OC_DIS (1 << 8) /* OTG Disable Overcurrent Event */
#define USB_UH1_OC_DIS (1 << 5) /* UH1 Disable Overcurrent Event */
+#define USB_UH1_OC_POL (1 << 6) /* UH1 Polarity of OC,Low active */
/* USB_PHY_CTRL_FUNC2*/
#define USB_UTMI_PHYCTRL2_PLLDIV_MASK 0x3
#define USB_UTMI_PHYCTRL2_PLLDIV_SHIFT 0
@@ -355,6 +358,8 @@
#define ULPIVW_WDATA_SHIFT 0
#define HCSPARAMS_PPC (0x1<<4) /* Port Power Control */
-
+/* USB Clock on/off Control Register */
+#define OTG_AHBCLK_OFF (0x1<<17) /* 1: OFF */
+#define H1_AHBCLK_OFF (0x1<<18) /* 1: OFF */
extern enum fsl_usb2_modes get_usb_mode(struct fsl_usb2_platform_data *pdata);
#endif
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h
index 742fb43592b7..990c3a00567c 100644
--- a/arch/arm/plat-mxc/include/mach/common.h
+++ b/arch/arm/plat-mxc/include/mach/common.h
@@ -34,6 +34,7 @@ extern int mx27_clocks_init(unsigned long fref);
extern int mx31_clocks_init(unsigned long fref);
extern int mx35_clocks_init(void);
extern int mx37_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2);
+extern int mx50_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih);
extern int mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2);
extern int mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2);
extern int mxc_init_devices(void);
diff --git a/arch/arm/plat-mxc/include/mach/fsl_usb.h b/arch/arm/plat-mxc/include/mach/fsl_usb.h
index d1235fc337ff..71263360dc69 100644
--- a/arch/arm/plat-mxc/include/mach/fsl_usb.h
+++ b/arch/arm/plat-mxc/include/mach/fsl_usb.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -88,4 +88,13 @@ static inline void fsl_platform_set_ahb_burst(struct usb_hcd *hcd)
writel((temp & (~(0x3f << 16))) | (0x20 << 16),
hcd->regs + FSL_SOC_USB_TXFILLTUNING);
}
+
+ /* Increase TX fifo threshold for USB+SD in Hostx */
+ if (cpu_is_mx53() && (strcmp("DR", pdata->name))) {
+ temp = readl(hcd->regs + FSL_SOC_USB_TXFILLTUNING);
+ /* Change TX FIFO threshold to be 0x08 */
+ writel((temp & (~(0x3f << 16))) | (0x08 << 16),
+ hcd->regs + FSL_SOC_USB_TXFILLTUNING);
+ }
+
}
diff --git a/arch/arm/plat-mxc/include/mach/hardware.h b/arch/arm/plat-mxc/include/mach/hardware.h
index e47a97bdfbd8..f48456869730 100644
--- a/arch/arm/plat-mxc/include/mach/hardware.h
+++ b/arch/arm/plat-mxc/include/mach/hardware.h
@@ -41,6 +41,7 @@
#define BOARD_REV_1 0x000
#define BOARD_REV_2 0x100
+#define BOARD_REV_3 0x200
#ifdef CONFIG_ARCH_MX3
#include <mach/mx3x.h>
@@ -85,6 +86,8 @@ extern unsigned int system_rev;
#ifdef CONFIG_ARCH_MX5
#define board_is_mx53_arm2() (cpu_is_mx53() && board_is_rev(BOARD_REV_2))
+#define board_is_mx53_evk_a() (cpu_is_mx53() && board_is_rev(BOARD_REV_1))
+#define board_is_mx53_evk_b() (cpu_is_mx53() && board_is_rev(BOARD_REV_3))
#endif
#include <mach/mxc.h>
diff --git a/arch/arm/plat-mxc/include/mach/iomux-v3.h b/arch/arm/plat-mxc/include/mach/iomux-v3.h
index 7cd84547658f..6beaf8cd69b5 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-v3.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-v3.h
@@ -68,33 +68,31 @@ struct pad_desc {
/*
* Use to set PAD control
*/
-#define PAD_CTL_DRIVE_VOLTAGE_3_3_V 0
-#define PAD_CTL_DRIVE_VOLTAGE_1_8_V 1
-#define PAD_CTL_NO_HYSTERESIS 0
-#define PAD_CTL_HYSTERESIS 1
+#define PAD_CTL_DVS (1 << 13)
+#define PAD_CTL_HYS (1 << 8)
-#define PAD_CTL_PULL_DISABLED 0x0
-#define PAD_CTL_PULL_KEEPER 0xa
-#define PAD_CTL_PULL_DOWN_100K 0xc
-#define PAD_CTL_PULL_UP_47K 0xd
-#define PAD_CTL_PULL_UP_100K 0xe
-#define PAD_CTL_PULL_UP_22K 0xf
+#define PAD_CTL_PKE (1 << 7)
+#define PAD_CTL_PUE (1 << 6)
+#define PAD_CTL_PUS_100K_DOWN (0 << 4)
+#define PAD_CTL_PUS_360K_DOWN (0 << 4)
+#define PAD_CTL_PUS_47K_UP (1 << 4)
+#define PAD_CTL_PUS_75K_UP (1 << 4)
+#define PAD_CTL_PUS_100K_UP (2 << 4)
+#define PAD_CTL_PUS_22K_UP (3 << 4)
-#define PAD_CTL_OUTPUT_CMOS 0
-#define PAD_CTL_OUTPUT_OPEN_DRAIN 1
+#define PAD_CTL_ODE (1 << 3)
-#define PAD_CTL_DRIVE_STRENGTH_NORM 0
-#define PAD_CTL_DRIVE_STRENGTH_HIGH 1
-#define PAD_CTL_DRIVE_STRENGTH_MAX 2
+#define PAD_CTL_DSE_LOW (0 << 1)
+#define PAD_CTL_DSE_MED (1 << 1)
+#define PAD_CTL_DSE_HIGH (2 << 1)
+#define PAD_CTL_DSE_MAX (3 << 1)
-#define PAD_CTL_SLEW_RATE_SLOW 0
-#define PAD_CTL_SLEW_RATE_FAST 1
+#define PAD_CTL_SRE_FAST (1 << 0)
+#define PAD_CTL_SRE_SLOW (0 << 0)
/*
- * setups a single pad:
- * - reserves the pad so that it is not claimed by another driver
- * - setups the iomux according to the configuration
+ * setups a single pad in the iomuxer
*/
int mxc_iomux_v3_setup_pad(struct pad_desc *pad);
@@ -105,17 +103,9 @@ int mxc_iomux_v3_setup_pad(struct pad_desc *pad);
int mxc_iomux_v3_setup_multiple_pads(struct pad_desc *pad_list, unsigned count);
/*
- * releases a single pad:
- * - make it available for a future use by another driver
- * - DOES NOT reconfigure the IOMUX in its reset state
+ * Initialise the iomux controller
*/
-void mxc_iomux_v3_release_pad(struct pad_desc *pad);
-
-/*
- * releases multiple pads
- * convenvient way to call the above function with tables
- */
-void mxc_iomux_v3_release_multiple_pads(struct pad_desc *pad_list, int count);
+void mxc_iomux_v3_init(void __iomem *iomux_v3_base);
#endif /* __MACH_IOMUX_V3_H__*/
diff --git a/arch/arm/plat-mxc/include/mach/memory.h b/arch/arm/plat-mxc/include/mach/memory.h
index 3861342d1be0..ff05850287af 100644
--- a/arch/arm/plat-mxc/include/mach/memory.h
+++ b/arch/arm/plat-mxc/include/mach/memory.h
@@ -32,6 +32,10 @@
#define PHYS_OFFSET UL(0x90000000)
#endif
+#ifdef CONFIG_ARCH_MX50
+#define PHYS_OFFSET UL(0x70000000)
+#endif
+
#ifdef CONFIG_ARCH_MX53
#define PHYS_OFFSET UL(0x70000000)
#endif
diff --git a/arch/arm/plat-mxc/include/mach/mmc.h b/arch/arm/plat-mxc/include/mach/mmc.h
index d563c157bad7..7be75bd5756e 100644
--- a/arch/arm/plat-mxc/include/mach/mmc.h
+++ b/arch/arm/plat-mxc/include/mach/mmc.h
@@ -40,6 +40,9 @@ struct mxc_mmc_platform_data {
unsigned int min_clk;
unsigned int max_clk;
unsigned int clk_flg; /* 1 clock enable, 0 not */
+ unsigned int clk_always_on; /* Needed by SDIO cards and etc */
+ unsigned int dll_override_en; /* Enable dll override delay line */
+ unsigned int dll_delay_cells; /* The number of delay cells (0-0x3f) */
unsigned int reserved:16;
unsigned int card_fixed:1;
unsigned int card_inserted_state:1;
diff --git a/arch/arm/plat-mxc/include/mach/mx37.h b/arch/arm/plat-mxc/include/mach/mx37.h
index 3013d197f206..d83bdfd8824b 100644
--- a/arch/arm/plat-mxc/include/mach/mx37.h
+++ b/arch/arm/plat-mxc/include/mach/mx37.h
@@ -225,6 +225,9 @@
#define WEIM_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DA000)
#define NFC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DB000)
+#define DPTCLP_BASE_ADDR (GPC_BASE_ADDR + 0x80)
+#define DPTCGP_BASE_ADDR (GPC_BASE_ADDR + 0x100)
+#define DVFSCORE_BASE_ADDR (GPC_BASE_ADDR + 0x180)
#define DVFSPER_BASE_ADDR (GPC_BASE_ADDR + 0x1C4)
/*
diff --git a/arch/arm/plat-mxc/include/mach/mx5x.h b/arch/arm/plat-mxc/include/mach/mx5x.h
index 5be0f426c7da..0e25133736d2 100644
--- a/arch/arm/plat-mxc/include/mach/mx5x.h
+++ b/arch/arm/plat-mxc/include/mach/mx5x.h
@@ -93,7 +93,7 @@
#endif
#ifdef CONFIG_MXC_VPU_IRAM
-#define VPU_IRAM_SIZE 0x11000
+#define VPU_IRAM_SIZE 0x14000
#else
#define VPU_IRAM_SIZE 0
#endif
@@ -129,6 +129,36 @@
#define MX51_TZIC_BASE_ADDR 0xE0000000
#define TZIC_SIZE SZ_16K
+/*
+ * AHCI SATA
+ */
+#define MX53_SATA_BASE_ADDR 0x10000000
+
+/*
+ * Databahn MX50
+ */
+#define MX50_DATABAHN_BASE_ADDR 0x14000000
+#define DATABAHN_CTL_REG19 0x4c
+#define DATABAHN_CTL_REG20 0x50
+#define DATABAHN_CTL_REG21 0x54
+#define DATABAHN_CTL_REG22 0x58
+#define DATABAHN_CTL_REG23 0x5c
+#define DATABAHN_CTL_REG42 0xa8
+#define DATABAHN_CTL_REG43 0xac
+#define DATABAHN_CTL_REG55 0xdc
+#define DATABAHN_CTL_REG63 0xFC
+#define LOWPOWER_CONTROL_MASK 0x1F
+#define LOWPOWER_AUTOENABLE_MASK 0x1F
+#define LOWPOWER_EXTERNAL_CNT_MASK (0xFFFF << 16)
+#define LOWPOWER_EXTERNAL_CNT_OFFSET 16
+#define LOWPOWER_INTERNAL_CNT_MASK (0xFFFF << 8)
+#define LOWPOWER_INTERNAL_CNT_OFFSET 8
+#define LOWPOWER_REFRESH_ENABLE_MASK (3 << 16)
+#define LOWPOWER_REFRESH_ENABLE_OFFSET 16
+#define LOWPOWER_REFRESH_HOLD_MASK 0xFFFF
+#define LOWPOWER_REFRESH_HOLD_OFFSET 0
+
+
#define DEBUG_BASE_ADDR 0x40000000
/*MX53 + 0x2000000 */
#define DEBUG_SIZE SZ_1M
@@ -141,6 +171,22 @@
#define CTI3_BASE_ADDR (DEBUG_BASE_ADDR + 0x00007000)
#define CORTEX_DBG_BASE_ADDR (DEBUG_BASE_ADDR + 0x00008000)
+#define APBHDMA_BASE_ADDR (DEBUG_BASE_ADDR + 0x01000000)
+#define OCOTP_CTRL_BASE_ADDR (DEBUG_BASE_ADDR + 0x01002000)
+#define DIGCTL_BASE_ADDR (DEBUG_BASE_ADDR + 0x01004000)
+#define GPMI_BASE_ADDR (DEBUG_BASE_ADDR + 0x01006000)
+#define BCH_BASE_ADDR (DEBUG_BASE_ADDR + 0x01008000)
+#define ELCDIF_BASE_ADDR (DEBUG_BASE_ADDR + 0x0100A000)
+#define EPXP_BASE_ADDR (DEBUG_BASE_ADDR + 0x0100C000)
+#define DCP_BASE_ADDR (DEBUG_BASE_ADDR + 0x0100E000)
+#define EPDC_BASE_ADDR (DEBUG_BASE_ADDR + 0x01010000)
+#define QOSC_BASE_ADDR (DEBUG_BASE_ADDR + 0x01012000)
+#define PERFMON_BASE_ADDR (DEBUG_BASE_ADDR + 0x01014000)
+#define SSP_BASE_ADDR (DEBUG_BASE_ADDR + 0x01016000)
+#define ANATOP_BASE_ADDR (DEBUG_BASE_ADDR + 0x01018000)
+
+#define MX50_NIC_BASE_ADDR (DEBUG_BASE_ADDR + 0x08000000)
+
/*
* SPBA global module enabled #0
*/
@@ -216,6 +262,7 @@
#define MX53_ATA_BASE_ADDR (AIPS1_BASE_ADDR + 0x000E8000)
#define I2C3_BASE_ADDR (AIPS1_BASE_ADDR + 0x000EC000)
#define UART4_BASE_ADDR (AIPS1_BASE_ADDR + 0x000F0000)
+#define RNGB_BASE_ADDR (AIPS1_BASE_ADDR + 0x000F8000) /* MX50 */
#define DVFSCORE_BASE_ADDR (GPC_BASE_ADDR + 0x180)
#define DVFSPER_BASE_ADDR (GPC_BASE_ADDR + 0x1C4)
@@ -371,7 +418,7 @@
#define NFC_AXI_IO_ADDRESS(x) \
(((x) - NFC_BASE_ADDR_AXI) + NFC_BASE_ADDR_AXI_VIRT)
-#define MX53_BASE_ADDR(x) (cpu_is_mx53() ? (x) - 0x20000000 : (x))
+#define MX53_BASE_ADDR(x) (cpu_is_mx53() || cpu_is_mx50() ? (x) - 0x20000000 : (x))
#define IS_MEM_DEVICE_NONSHARED(x) 0
@@ -388,6 +435,8 @@
#define DMA_REQ_SLIM_B_TX 42 /* MX51 */
#define DMA_REQ_UART3_TX_MX51 44
#define DMA_REQ_UART3_RX_MX51 43
+#define DMA_REQ_UART3_TX_MX50 43
+#define DMA_REQ_UART3_RX_MX50 42
#define DMA_REQ_ESAI_TX 41
#define DMA_REQ_SDHC4_MX51 41
#define DMA_REQ_ESAI_RX 40
@@ -434,9 +483,13 @@
#define DMA_REQ_UART5_RX 16
#define DMA_REQ_SPDIF_TX 15
#define DMA_REQ_SPDIF_RX 14
+#define DMA_REQ_EXTREQ0_MX50 14
+#define DMA_REQ_EXTREQ1_MX50 15
/* UART2 is shared w/FIRI on MX53 */
#define DMA_REQ_FIRI_TX 13
#define DMA_REQ_FIRI_RX 12
+#define DMA_REQ_UART2_TX_MX50 13
+#define DMA_REQ_UART2_RX_MX50 12
#define DMA_REQ_SDHC4_MX53 11
#define DMA_REQ_HS_I2C_RX 11 /* MX51 */
@@ -453,7 +506,9 @@
#define DMA_REQ_SLIM_B 5 /* MX51 */
#define DMA_REQ_ATA_TX_END 4
#define DMA_REQ_ATA_TX 3
+#define DMA_REQ_UART4_TX_MX50 3
#define DMA_REQ_ATA_RX 2
+#define DMA_REQ_UART4_RX_MX50 2
#define DMA_REQ_GPC 1
#define DMA_REQ_VPU 0
@@ -481,16 +536,21 @@
#define MXC_INT_USB_H3 17
#define MXC_INT_USB_OTG 18
#define MXC_INT_SAHARA_H0 19
+#define MXC_INT_DATABAHN 19 /* MX50 */
#define MXC_INT_SAHARA_H1 20
+#define MXC_INT_ELCDIF 20 /* MX50 */
#define MXC_INT_SCC_SMN 21
+#define MXC_INT_EPXP 21 /* MX50 */
#define MXC_INT_SCC_STZ 22
#define MXC_INT_SCC_SCM 23
#define MXC_INT_SRTC_NTZ 24
#define MXC_INT_SRTC_TZ 25
#define MXC_INT_RTIC 26
#define MXC_INT_CSU 27
+#define MXC_INT_EPDC 27 /* MX50 */
#define MXC_INT_SATA 28
#define MXC_INT_SLIM_B 28 /* MX51 */
+#define MXC_INT_NIC 28 /* MX50 Perfmon IRQ */
#define MXC_INT_SSI1 29
#define MXC_INT_SSI2 30
#define MXC_INT_UART1 31
@@ -534,6 +594,10 @@
#define MXC_INT_SIM_IPB 67
#define MXC_INT_SIM_DAT 68
#define MXC_INT_IIM 69
+#define MXC_INT_ANATOP1 66 /* MX50 what's it? */
+#define MXC_INT_ANATOP2 67
+#define MXC_INT_ANATOP3 68
+#define MXC_INT_ANATOP4 69
#define MXC_INT_ATA 70
#define MXC_INT_CCM1 71
#define MXC_INT_CCM2 72
@@ -559,23 +623,46 @@
#define MXC_INT_CTI1_TG2 89
#define MXC_INT_SJC 90
#define MXC_INT_SPDIF_MX51 91
+#define MXC_INT_DCP_CHAN1_3 91 /* MX50 */
#define MXC_INT_TVE 92
+#define MXC_INT_DCP_CHAN0 92 /* MX50 */
#define MXC_INT_FIRI 93
+#define MXC_INT_DCP_CHAN0_3_SEC 93 /* MX50 */
#define MXC_INT_PWM2 94
#define MXC_INT_SLIM_EXP 95
#define MXC_INT_SSI3 96
#define MXC_INT_EMI_BOOT 97
+#define MXC_INT_RNGB_BLOCK 97 /* MX50 */
#define MXC_INT_CTI1_TG3 98
#define MXC_INT_SMC_RX 99
#define MXC_INT_VPU_IDLE 100
+#define MXC_INT_RAWNAND_BCH 100 /* MX50 */
#define MXC_INT_EMI_NFC 101
#define MXC_INT_GPU_IDLE 102
+#define MXC_INT_RAWNAND_GPMI 102 /* MX50 */
#define MXC_INT_GPIO5_LOW 103
#define MXC_INT_GPIO5_HIGH 104
#define MXC_INT_GPIO6_LOW 105
#define MXC_INT_GPIO6_HIGH 106
#define MXC_INT_GPIO7_LOW 107
#define MXC_INT_GPIO7_HIGH 108
+#define MXC_INT_MSHC 109 /* MX50 */
+#define MXC_INT_APBHDMA_CHAN0 110
+#define MXC_INT_APBHDMA_CHAN1 111
+#define MXC_INT_APBHDMA_CHAN2 112
+#define MXC_INT_APBHDMA_CHAN3 113
+#define MXC_INT_APBHDMA_CHAN4 114
+#define MXC_INT_APBHDMA_CHAN5 115
+#define MXC_INT_APBHDMA_CHAN6 116
+#define MXC_INT_APBHDMA_CHAN7 117
+#define MXC_INT_APBHDMA_CHAN8 118
+#define MXC_INT_APBHDMA_CHAN9 119
+#define MXC_INT_APBHDMA_CHAN10 120
+#define MXC_INT_APBHDMA_CHAN11 121
+#define MXC_INT_APBHDMA_CHAN12 122
+#define MXC_INT_APBHDMA_CHAN13 123
+#define MXC_INT_APBHDMA_CHAN14 124
+#define MXC_INT_APBHDMA_CHAN15 125
/* gpio and gpio based interrupt handling */
#define GPIO_DR 0x00
diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h
index a47e599c54d4..808adf67552d 100644
--- a/arch/arm/plat-mxc/include/mach/mxc.h
+++ b/arch/arm/plat-mxc/include/mach/mxc.h
@@ -34,6 +34,7 @@
#define MXC_CPU_MX37 37
#define MXC_CPU_MX51 51
#define MXC_CPU_MX53 53
+#define MXC_CPU_MX50 50
#ifndef __ASSEMBLY__
extern unsigned int __mxc_cpu_type;
@@ -147,6 +148,18 @@ extern unsigned int __mxc_cpu_type;
# define cpu_is_mx53() (0)
#endif
+#ifdef CONFIG_ARCH_MX50
+# ifdef mxc_cpu_type
+# undef mxc_cpu_type
+# define mxc_cpu_type __mxc_cpu_type
+# else
+# define mxc_cpu_type MXC_CPU_MX50
+# endif
+# define cpu_is_mx50() (mxc_cpu_type == MXC_CPU_MX50)
+#else
+# define cpu_is_mx50() (0)
+#endif
+
#define cpu_is_mx32() (0)
/*
@@ -222,6 +235,7 @@ struct mxc_ipu_config {
int rev;
void (*reset) (void);
struct clk *di_clk[2];
+ struct clk *csi_clk[2];
};
struct mxc_ir_platform_data {
@@ -292,6 +306,7 @@ struct mxc_lightsensor_platform_data {
struct mxc_fb_platform_data {
struct fb_videomode *mode;
+ int num_modes;
char *mode_str;
u32 interface_pix_fmt;
};
@@ -306,8 +321,32 @@ struct mxc_lcd_platform_data {
struct ccwmx51_lcd_pdata {
int vif;
struct mxc_fb_platform_data fb_pdata;
- void (*reset) (void);
- void (*bl_enable) (int);
+ void (*init) (int);
+ void (*deinit) (int);
+ void (*bl_enable) (int, int);
+};
+
+struct mxc_epdc_fb_mode {
+ struct fb_videomode *vmode;
+ int vscan_holdoff;
+ int sdoed_width;
+ int sdoed_delay;
+ int sdoez_width;
+ int sdoez_delay;
+ int gdclk_hp_offs;
+ int gdsp_offs;
+ int gdoe_offs;
+ int gdclk_offs;
+ int num_ce;
+};
+
+struct mxc_epdc_fb_platform_data {
+ struct mxc_epdc_fb_mode *epdc_mode;
+ int num_modes;
+ void (*get_pins) (void);
+ void (*put_pins) (void);
+ void (*enable_pins) (void);
+ void (*disable_pins) (void);
};
struct mxc_tsc_platform_data {
@@ -346,6 +385,7 @@ struct mxc_camera_platform_data {
char *gpo_regulator;
u32 mclk;
u32 csi;
+ void (*pwdn) (int pwdn);
};
/*gpo1-3 is in fixed state by hardware design,
@@ -465,10 +505,20 @@ struct tve_platform_data {
char *dig_reg;
};
+struct ldb_platform_data {
+ char *lvds_bg_reg;
+ u32 ext_ref;
+};
+
struct mxc_vpu_platform_data {
void (*reset) (void);
};
+struct mxc_esai_platform_data {
+ void (*activate_esai_ports) (void);
+ void (*deactivate_esai_ports) (void);
+};
+
/* The name that links the i.MX NAND Flash Controller driver to its devices. */
#define IMX_NFC_DRIVER_NAME ("imx_nfc")
@@ -584,6 +634,18 @@ struct mxc_sim_platform_data {
unsigned int detect; /* 1 have detect pin, 0 not */
};
+struct fsl_otp_data {
+ char **fuse_name;
+ char *regulator_name;
+ unsigned int fuse_num;
+};
+
+struct mxs_dma_plat_data {
+ unsigned int burst8:1;
+ unsigned int burst:1;
+ unsigned int chan_base;
+ unsigned int chan_num;
+};
#endif /* __ASSEMBLY__ */
#define MUX_IO_P 29
@@ -649,7 +711,7 @@ void gpio_deactivate_esai_ports(void);
#define CSCR_A(n) (IO_ADDRESS(WEIM_BASE_ADDR) + n * 0x10 + 0x8)
#endif
-#define cpu_is_mx5() (cpu_is_mx51() || cpu_is_mx53())
+#define cpu_is_mx5() (cpu_is_mx51() || cpu_is_mx53() || cpu_is_mx50())
#define cpu_is_mx3() (cpu_is_mx31() || cpu_is_mx35())
#define cpu_is_mx2() (cpu_is_mx21() || cpu_is_mx27())
diff --git a/arch/arm/plat-mxc/include/mach/mxc_dvfs.h b/arch/arm/plat-mxc/include/mach/mxc_dvfs.h
index fd0179b4d8f9..05c6ea4bda77 100644
--- a/arch/arm/plat-mxc/include/mach/mxc_dvfs.h
+++ b/arch/arm/plat-mxc/include/mach/mxc_dvfs.h
@@ -35,6 +35,7 @@
#include <linux/device.h>
extern void __iomem *gpc_base;
+extern void __iomem *ccm_base;
#define MXC_GPCCNTR_GPCIRQ2M (1 << 25)
#define MXC_GPCCNTR_GPCIRQ2 (1 << 24)
@@ -101,6 +102,25 @@ extern void __iomem *gpc_base;
#define MXC_DVFSPMCR1_P4PM 0x00020000
#define MXC_DVFSPMCR1_P2PM 0x00010000
+/* DVFS CORE register offsets*/
+#define MXC_DVFSCORE_THRS 0x00
+#define MXC_DVFSCORE_COUN 0x04
+#define MXC_DVFSCORE_SIG1 0x08
+#define MXC_DVFSCORE_SIG0 0x0C
+#define MXC_DVFSCORE_GPC0 0x10
+#define MXC_DVFSCORE_GPC1 0x14
+#define MXC_DVFSCORE_GPBT 0x18
+#define MXC_DVFSCORE_EMAC 0x1C
+#define MXC_DVFSCORE_CNTR 0x20
+#define MXC_DVFSCORE_LTR0_0 0x24
+#define MXC_DVFSCORE_LTR0_1 0x28
+#define MXC_DVFSCORE_LTR1_0 0x2C
+#define MXC_DVFSCORE_LTR1_1 0x30
+#define MXC_DVFSCORE_PT0 0x34
+#define MXC_DVFSCORE_PT1 0x38
+#define MXC_DVFSCORE_PT2 0x3C
+#define MXC_DVFSCORE_PT3 0x40
+
/*
* DVFS structure
*/
@@ -120,24 +140,20 @@ struct mxc_dvfs_platform_data {
char *clk1_id;
/* DVFS clock name string */
char *clk2_id;
- /* GPC control reg address */
- void __iomem *gpc_cntr_reg_addr;
- /* GPC voltage counter reg address */
- void __iomem *gpc_vcr_reg_addr;
- /* CCM DVFS control reg address */
- void __iomem *ccm_cdcr_reg_addr;
- /* CCM ARM clock root reg address */
- void __iomem *ccm_cacrr_reg_addr;
- /* CCM divider handshake in-progree reg address */
- void __iomem *ccm_cdhipr_reg_addr;
- /* DVFS threshold reg address */
- void __iomem *dvfs_thrs_reg_addr;
- /* DVFS counters reg address */
- void __iomem *dvfs_coun_reg_addr;
- /* DVFS EMAC reg address */
- void __iomem *dvfs_emac_reg_addr;
- /* DVFS control reg address */
- void __iomem *dvfs_cntr_reg_addr;
+ /* The base address of the DVFS core */
+ void __iomem *membase;
+ /* The interrupt number used by the DVFS core */
+ int irq;
+ /* GPC control reg offset */
+ int gpc_cntr_offset;
+ /* GPC voltage counter reg offset */
+ int gpc_vcr_offset;
+ /* CCM DVFS control reg offset */
+ int ccm_cdcr_offset;
+ /* CCM ARM clock root reg offset */
+ int ccm_cacrr_offset;
+ /* CCM divider handshake in-progress reg offset */
+ int ccm_cdhipr_offset;
/* PREDIV mask */
u32 prediv_mask;
/* PREDIV offset */
@@ -182,6 +198,8 @@ struct mxc_dvfsper_data {
char *reg_id;
/* DVFS clock name string */
char *clk_id;
+ /* The base address of the DVFS per */
+ void __iomem *membase;
/* GPC control reg address */
void __iomem *gpc_cntr_reg_addr;
/* GPC VCR reg address */
diff --git a/arch/arm/plat-mxc/include/mach/system.h b/arch/arm/plat-mxc/include/mach/system.h
index 126bc8713159..604abbc77da0 100644
--- a/arch/arm/plat-mxc/include/mach/system.h
+++ b/arch/arm/plat-mxc/include/mach/system.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd
- * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2010 Freescale Semiconductor, Inc.
*
* 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
@@ -24,5 +24,6 @@
extern void arch_idle(void);
void arch_reset(char mode, const char *cmd);
+int mxs_reset_block(void __iomem *hwreg, int just_enable);
#endif /* __ASM_ARCH_MXC_SYSTEM_H__ */
diff --git a/arch/arm/plat-mxc/iomux-v3.c b/arch/arm/plat-mxc/iomux-v3.c
index 77a078f9513f..b318c6a222d5 100644
--- a/arch/arm/plat-mxc/iomux-v3.c
+++ b/arch/arm/plat-mxc/iomux-v3.c
@@ -29,30 +29,22 @@
#include <asm/mach/map.h>
#include <mach/iomux-v3.h>
-#define IOMUX_BASE IO_ADDRESS(IOMUXC_BASE_ADDR)
-
-static unsigned long iomux_v3_pad_alloc_map[0x200 / BITS_PER_LONG];
+static void __iomem *base;
/*
- * setups a single pin:
- * - reserves the pin so that it is not claimed by another driver
- * - setups the iomux according to the configuration
+ * setups a single pad in the iomuxer
*/
int mxc_iomux_v3_setup_pad(struct pad_desc *pad)
{
- unsigned int pad_ofs = pad->pad_ctrl_ofs;
-
- if (test_and_set_bit(pad_ofs >> 2, iomux_v3_pad_alloc_map))
- return -EBUSY;
if (pad->mux_ctrl_ofs)
- __raw_writel(pad->mux_mode, IOMUX_BASE + pad->mux_ctrl_ofs);
+ __raw_writel(pad->mux_mode, base + pad->mux_ctrl_ofs);
if (pad->select_input_ofs)
__raw_writel(pad->select_input,
- IOMUX_BASE + pad->select_input_ofs);
+ base + pad->select_input_ofs);
- if (!(pad->pad_ctrl & NO_PAD_CTRL))
- __raw_writel(pad->pad_ctrl, IOMUX_BASE + pad->pad_ctrl_ofs);
+ if (!(pad->pad_ctrl & NO_PAD_CTRL) && pad->pad_ctrl_ofs)
+ __raw_writel(pad->pad_ctrl, base + pad->pad_ctrl_ofs);
return 0;
}
EXPORT_SYMBOL(mxc_iomux_v3_setup_pad);
@@ -66,33 +58,14 @@ int mxc_iomux_v3_setup_multiple_pads(struct pad_desc *pad_list, unsigned count)
for (i = 0; i < count; i++) {
ret = mxc_iomux_v3_setup_pad(p);
if (ret)
- goto setup_error;
+ return ret;
p++;
}
return 0;
-
-setup_error:
- mxc_iomux_v3_release_multiple_pads(pad_list, i);
- return ret;
}
EXPORT_SYMBOL(mxc_iomux_v3_setup_multiple_pads);
-void mxc_iomux_v3_release_pad(struct pad_desc *pad)
-{
- unsigned int pad_ofs = pad->pad_ctrl_ofs;
-
- clear_bit(pad_ofs >> 2, iomux_v3_pad_alloc_map);
-}
-EXPORT_SYMBOL(mxc_iomux_v3_release_pad);
-
-void mxc_iomux_v3_release_multiple_pads(struct pad_desc *pad_list, int count)
+void mxc_iomux_v3_init(void __iomem *iomux_v3_base)
{
- struct pad_desc *p = pad_list;
- int i;
-
- for (i = 0; i < count; i++) {
- mxc_iomux_v3_release_pad(p);
- p++;
- }
+ base = iomux_v3_base;
}
-EXPORT_SYMBOL(mxc_iomux_v3_release_multiple_pads);
diff --git a/arch/arm/plat-mxc/iram.c b/arch/arm/plat-mxc/iram.c
index 3d2a391bd2d1..c63b0a2a9a10 100644
--- a/arch/arm/plat-mxc/iram.c
+++ b/arch/arm/plat-mxc/iram.c
@@ -36,6 +36,11 @@ void *iram_alloc(unsigned int size, unsigned long *dma_addr)
*dma_addr = gen_pool_alloc(iram_pool, size);
pr_debug("iram alloc - %dB@0x%p\n", size, (void *)*dma_addr);
+
+ WARN_ON(!*dma_addr);
+ if (!*dma_addr)
+ return NULL;
+
return iram_phys_to_virt(*dma_addr);
}
EXPORT_SYMBOL(iram_alloc);
diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c
index f159feb01f83..77eb52ce477c 100644
--- a/arch/arm/plat-mxc/pwm.c
+++ b/arch/arm/plat-mxc/pwm.c
@@ -61,7 +61,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
return -EINVAL;
- if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx51() || cpu_is_mx53()) {
+ if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx5()) {
unsigned long long c;
unsigned long period_cycles, duty_cycles, prescale;
c = clk_get_rate(pwm->clk);
diff --git a/arch/arm/plat-mxc/usb_common.c b/arch/arm/plat-mxc/usb_common.c
index 2f5f597f806e..71583e465046 100644
--- a/arch/arm/plat-mxc/usb_common.c
+++ b/arch/arm/plat-mxc/usb_common.c
@@ -275,21 +275,25 @@ static void usbh1_set_utmi_xcvr(void)
while ((UH1_USBCMD) & (UCMD_RESET))
;
- /* MX53 EVK is not using OC */
- USB_PHY_CTR_FUNC |= USB_UH1_OC_DIS;
-
- USBCTRL &= ~UCTRL_H1PM; /* OTG Power Mask */
- USBCTRL &= ~UCTRL_H1WIE; /* OTG Wakeup Intr Disable */
-
- /* Over current disable */
- USB_PHY_CTR_FUNC |= (0x1 << 5);
-
+ /* For OC and PWR, it is board level setting
+ * The default setting is for mx53 evk
+ */
+ USBCTRL &= ~UCTRL_H1PM; /* Host1 Power Mask */
+ USBCTRL &= ~UCTRL_H1WIE; /* Host1 Wakeup Intr Disable */
+ USB_PHY_CTR_FUNC |= USB_UH1_OC_DIS; /* Over current disable */
+
+ if (machine_is_mx50_arm2()) {
+ USBCTRL |= UCTRL_H1PM; /* Host1 Power Mask */
+ USB_PHY_CTR_FUNC &= ~USB_UH1_OC_DIS; /* Over current enable */
+ /* Over current polarity low active */
+ USB_PHY_CTR_FUNC |= USB_UH1_OC_POL;
+ }
/* set UTMI xcvr */
tmp = UH1_PORTSC1 & ~PORTSC_PTS_MASK;
tmp |= PORTSC_PTS_UTMI;
UH1_PORTSC1 = tmp;
- /* Set the PHY clock to 19.2MHz */
+ /* Set the PHY clock to 24MHz */
USBH1_PHY_CTRL1 &= ~USB_UTMI_PHYCTRL2_PLLDIV_MASK;
USBH1_PHY_CTRL1 |= 0x01;
@@ -428,14 +432,7 @@ static int usb_register_remote_wakeup(struct platform_device *pdev)
int irq;
pr_debug("%s: pdev=0x%p \n", __func__, pdev);
- if (!cpu_is_mx51() && !cpu_is_mx25())
- return -ECANCELED;
-
- /* The Host2 USB controller On mx25 platform
- * is no path available from internal USB FS
- * PHY to FS PHY wake up interrupt, So to
- * remove the function of USB Remote Wakeup on Host2 */
- if (cpu_is_mx25() && (!strcmp("Host 2", pdata->name)))
+ if (!(pdata->wake_up_enable))
return -ECANCELED;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -485,6 +482,10 @@ int fsl_usb_host_init(struct platform_device *pdev)
clk_put(usboh3_clk);
}
+ if (cpu_is_mx50())
+ /* Turn on AHB CLK for H1*/
+ USB_CLKONOFF_CTRL &= ~H1_AHBCLK_OFF;
+
/* enable board power supply for xcvr */
if (pdata->xcvr_pwr) {
if (pdata->xcvr_pwr->regu1)
@@ -704,6 +705,11 @@ static void otg_set_utmi_xcvr(void)
} else if (cpu_is_mx25()) {
USBCTRL |= UCTRL_OCPOL;
USBCTRL &= ~UCTRL_PP;
+ } else if (cpu_is_mx50()) {
+ USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_OC_DIS;
+ if (machine_is_mx50_arm2())
+ /* OTG Power pin polarity low */
+ USBCTRL |= UCTRL_O_PWR_POL;
} else {
/* USBOTG_PWR low active */
USBCTRL &= ~UCTRL_PP;
@@ -715,8 +721,9 @@ static void otg_set_utmi_xcvr(void)
USBCTRL |= UCTRL_OLOCKD;
}
- if (!cpu_is_mx53())
+ if (cpu_is_mx51())
USBCTRL &= ~UCTRL_OPM; /* OTG Power Mask */
+
USBCTRL &= ~UCTRL_OWIE; /* OTG Wakeup Intr Disable */
/* set UTMI xcvr */
@@ -793,9 +800,12 @@ int usbotg_init(struct platform_device *pdev)
pdata->xcvr_type = xops->xcvr_type;
pdata->pdev = pdev;
+ if (fsl_check_usbclk() != 0)
+ return -EINVAL;
if (!otg_used) {
- if (fsl_check_usbclk() != 0)
- return -EINVAL;
+ if (cpu_is_mx50())
+ /* Turn on AHB CLK for OTG*/
+ USB_CLKONOFF_CTRL &= ~OTG_AHBCLK_OFF;
pr_debug("%s: grab pins\n", __func__);
if (pdata->gpio_usb_active && pdata->gpio_usb_active())
@@ -871,8 +881,8 @@ int usb_host_wakeup_irq(struct device *wkup_dev)
wakeup_req = USBCTRL & UCTRL_H1WIR;
} else if (!strcmp("DR", pdata->name)) {
wakeup_req = USBCTRL & UCTRL_OWIR;
- /* If DR is in device mode, let udc handle it */
- if (wakeup_req && ((UOG_USBMODE & 0x3) == 0x2))
+ /* If not ID wakeup, let udc handle it */
+ if (wakeup_req && (UOG_OTGSC & OTGSC_STS_USB_ID))
wakeup_req = 0;
}
diff --git a/arch/arm/plat-mxc/utmixc.c b/arch/arm/plat-mxc/utmixc.c
index 6a13e8fbbe70..59207ab9ff67 100644
--- a/arch/arm/plat-mxc/utmixc.c
+++ b/arch/arm/plat-mxc/utmixc.c
@@ -73,6 +73,8 @@ static void set_power(struct fsl_xcvr_ops *this,
regulator_put(usbotg_regux);
}
}
+ if (pdata && pdata->platform_driver_vbus)
+ pdata->platform_driver_vbus(on);
}
static struct fsl_xcvr_ops utmi_ops = {
diff --git a/arch/arm/plat-mxs/Kconfig b/arch/arm/plat-mxs/Kconfig
index dd6689ecf5d0..63768f85a327 100644
--- a/arch/arm/plat-mxs/Kconfig
+++ b/arch/arm/plat-mxs/Kconfig
@@ -19,6 +19,7 @@ config ARCH_MX28
config ARCH_MX23
bool "Freescale MX23"
select CPU_ARM926T
+ select FIQ
select ZONE_DMA
select MXS_ICOLL
select MXS_DMA_ENGINE
diff --git a/arch/arm/plat-mxs/Makefile b/arch/arm/plat-mxs/Makefile
index 2c271285bdfd..e252630479d9 100644
--- a/arch/arm/plat-mxs/Makefile
+++ b/arch/arm/plat-mxs/Makefile
@@ -8,6 +8,8 @@ obj-$(CONFIG_MXS_TIMER_WITH_MACH) += timer-match.o
obj-$(CONFIG_IRAM_ALLOC) += iram.o
obj-$(CONFIG_GENERIC_GPIO) += gpio.o
+obj-$(CONFIG_MXS_UNIQUE_ID) += unique-id.o
+
obj-$(CONFIG_MXS_ICOLL) += icoll.o
obj-$(CONFIG_MXS_DMA_ENGINE) += dmaengine.o dma-apbh.o dma-apbx.o
diff --git a/arch/arm/plat-mxs/clock.c b/arch/arm/plat-mxs/clock.c
index 9fecdbde49ad..1b98b1e51164 100644
--- a/arch/arm/plat-mxs/clock.c
+++ b/arch/arm/plat-mxs/clock.c
@@ -29,6 +29,9 @@
#include <mach/clock.h>
extern int cpufreq_trig_needed;
+static bool (*mxs_enable_h_autoslow)(bool enable);
+static void (*mxs_set_h_autoslow_flags)(u16 flags);
+
static DEFINE_SPINLOCK(clockfw_lock);
/*
@@ -109,7 +112,11 @@ int clk_enable(struct clk *clk)
return -EINVAL;
spin_lock_irqsave(&clockfw_lock, flags);
- pre_usage = clk->ref;
+ pre_usage = (clk->ref & CLK_EN_MASK);
+
+ if (clk->set_sys_dependent_parent)
+ clk->set_sys_dependent_parent(clk);
+
ret = __clk_enable(clk);
spin_unlock_irqrestore(&clockfw_lock, flags);
if ((clk->flags & CPU_FREQ_TRIG_UPDATE)
@@ -133,7 +140,7 @@ void clk_disable(struct clk *clk)
__clk_disable(clk);
spin_unlock_irqrestore(&clockfw_lock, flags);
if ((clk->flags & CPU_FREQ_TRIG_UPDATE)
- && (clk->ref == 0)) {
+ && ((clk->ref & CLK_EN_MASK) == 0)) {
cpufreq_trig_needed = 1;
cpufreq_update_policy(0);
}
@@ -279,3 +286,40 @@ void clk_unregister(struct clk_lookup *lookup)
lookup->clk->get_rate = NULL;
}
EXPORT_SYMBOL(clk_unregister);
+
+bool clk_enable_h_autoslow(bool enable)
+{
+ unsigned long flags;
+ bool ret = false;
+
+ if (mxs_enable_h_autoslow == NULL)
+ return ret;
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+ ret = mxs_enable_h_autoslow(enable);
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(clk_enable_h_autoslow);
+
+void clk_set_h_autoslow_flags(u16 mask)
+{
+ unsigned long flags;
+
+ if (mxs_set_h_autoslow_flags == NULL)
+ return;
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+ mxs_set_h_autoslow_flags(mask);
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_set_h_autoslow_flags);
+
+void clk_en_public_h_asm_ctrl(bool (*enable_func)(bool),
+ void (*set_func)(u16))
+{
+ mxs_enable_h_autoslow = enable_func;
+ mxs_set_h_autoslow_flags = set_func;
+}
+EXPORT_SYMBOL(clk_en_public_h_asm_ctrl);
diff --git a/arch/arm/plat-mxs/cpufreq.c b/arch/arm/plat-mxs/cpufreq.c
index d36baa740dbc..a188b21d9bf4 100644
--- a/arch/arm/plat-mxs/cpufreq.c
+++ b/arch/arm/plat-mxs/cpufreq.c
@@ -40,6 +40,7 @@
static struct regulator *cpu_regulator;
static struct clk *cpu_clk;
static struct clk *ahb_clk;
+static struct clk *x_clk;
static struct clk *emi_clk;
static struct regulator *vddd;
static struct regulator *vdddbo;
@@ -62,11 +63,19 @@ static int set_freq_table(struct cpufreq_policy *policy, int end_index)
{
int ret = 0;
int i;
+ int zero_no = 0;
+
+ for (i = 0; i < end_index; i++) {
+ if (profiles[i].cpu == 0)
+ zero_no++;
+ }
+
+ end_index -= zero_no;
cpu_freq_khz_min = profiles[0].cpu;
cpu_freq_khz_max = profiles[0].cpu;
for (i = 0; i < end_index; i++) {
- imx_freq_table[end_index - 1 - i].index = end_index - i;
+ imx_freq_table[end_index - 1 - i].index = end_index - i;
imx_freq_table[end_index - 1 - i].frequency =
profiles[i].cpu;
@@ -135,8 +144,6 @@ static int set_op(struct cpufreq_policy *policy, unsigned int target_freq)
return 0;
}
- cpu_clk_set_pll_on(cpu_clk, freqs.new);
-
if (cpu_regulator && (freqs.old < freqs.new)) {
ret = regulator_set_current_limit(cpu_regulator,
profiles[i].cur, profiles[i].cur);
@@ -149,10 +156,16 @@ static int set_op(struct cpufreq_policy *policy, unsigned int target_freq)
if (freqs.old > freqs.new) {
int ss = profiles[i].ss;
+ /* change emi while cpu is fastest to minimize
+ * time spent changing emiclk
+ */
+ clk_set_rate(emi_clk, (profiles[i].emi) * 1000);
clk_set_rate(cpu_clk, (profiles[i].cpu) * 1000);
clk_set_rate(ahb_clk, (profiles[i].ahb) * 1000);
- clk_set_rate(emi_clk, (profiles[i].emi) * 1000);
+ /* x_clk order doesn't really matter */
+ clk_set_rate(x_clk, (profiles[i].xbus) * 1000);
timing_ctrl_rams(ss);
+
if (vddd && vdddbo && vddio && vdda) {
ret = regulator_set_voltage(vddd,
profiles[i].vddd,
@@ -208,17 +221,18 @@ static int set_op(struct cpufreq_policy *policy, unsigned int target_freq)
profiles[i].vdda,
profiles[i].vdda);
}
+ /* x_clk order doesn't really matter */
+ clk_set_rate(x_clk, (profiles[i].xbus) * 1000);
timing_ctrl_rams(ss);
- if (freqs.old == 64000)
- clk_set_rate(ahb_clk, (profiles[i].ahb) * 1000);
clk_set_rate(cpu_clk, (profiles[i].cpu) * 1000);
- if (freqs.old != 64000)
- clk_set_rate(ahb_clk, (profiles[i].ahb) * 1000);
+ clk_set_rate(ahb_clk, (profiles[i].ahb) * 1000);
clk_set_rate(emi_clk, (profiles[i].emi) * 1000);
}
- udelay(100);
- cpu_clk_set_pll_off(cpu_clk, freqs.new);
+ if (is_hclk_autoslow_ok())
+ clk_set_h_autoslow_flags(profiles[i].h_autoslow_flags);
+ else
+ clk_enable_h_autoslow(false);
if (high_freq_needed == 0)
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
@@ -231,7 +245,6 @@ static int set_op(struct cpufreq_policy *policy, unsigned int target_freq)
if (high_freq_needed == 1) {
high_freq_needed = 0;
cur_freq_table_size = lcd_on_freq_table_size;
- hbus_auto_slow_mode_disable();
set_freq_table(policy, cur_freq_table_size);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
@@ -293,11 +306,22 @@ static int mxs_target(struct cpufreq_policy *policy,
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
low_freq_bus_ready = low_freq_used();
if (low_freq_bus_ready) {
+ int i;
cur_freq_table_size = lcd_off_freq_table_size;
- hbus_auto_slow_mode_enable();
+ /* find current table index to get
+ * hbus autoslow flags and enable hbus autoslow.
+ */
+ for (i = cur_freq_table_size - 1; i > 0; i--) {
+ if (profiles[i].cpu <= target_freq &&
+ target_freq < profiles[i - 1].cpu) {
+ clk_set_h_autoslow_flags(
+ profiles[i].h_autoslow_flags);
+ break;
+ }
+ }
} else {
cur_freq_table_size = lcd_on_freq_table_size;
- hbus_auto_slow_mode_disable();
+ clk_enable_h_autoslow(false);
}
set_freq_table(policy, cur_freq_table_size);
@@ -354,6 +378,12 @@ static int __init mxs_cpu_init(struct cpufreq_policy *policy)
goto out_ahb;
}
+ x_clk = clk_get(NULL, "x");
+ if (IS_ERR(ahb_clk)) {
+ ret = PTR_ERR(x_clk);
+ goto out_x;
+ }
+
emi_clk = clk_get(NULL, "emi");
if (IS_ERR(emi_clk)) {
ret = PTR_ERR(emi_clk);
@@ -419,13 +449,13 @@ static int __init mxs_cpu_init(struct cpufreq_policy *policy)
for (i = 0; i < ARRAY_SIZE(profiles); i++) {
if ((profiles[i].cpu) == 0) {
- lcd_off_freq_table_size = i + 1;
+ lcd_off_freq_table_size = i;
break;
}
}
if (i == ARRAY_SIZE(profiles))
- lcd_off_freq_table_size = i + 1;
+ lcd_off_freq_table_size = i;
/* Set the current working point. */
set_freq_table(policy, lcd_on_freq_table_size);
@@ -447,6 +477,8 @@ out_cur:
clk_put(emi_clk);
out_emi:
+ clk_put(x_clk);
+out_x:
clk_put(ahb_clk);
out_ahb:
clk_put(cpu_clk);
diff --git a/arch/arm/plat-mxs/device.c b/arch/arm/plat-mxs/device.c
index 00180846885b..e3783d3fe87d 100644
--- a/arch/arm/plat-mxs/device.c
+++ b/arch/arm/plat-mxs/device.c
@@ -24,6 +24,7 @@
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/gpmi-nfc.h>
#include <mach/device.h>
@@ -138,10 +139,10 @@ static struct platform_device mxs_i2c[] = {
};
#endif
-#if defined(CONFIG_MTD_NAND_GPMI1) || \
- defined(CONFIG_MTD_NAND_GPMI1_MODULE)
-static struct platform_device mxs_gpmi = {
- .name = "gpmi",
+#if defined(CONFIG_MTD_NAND_GPMI_NFC) || \
+ defined(CONFIG_MTD_NAND_GPMI_NFC_MODULE)
+static struct platform_device gpmi_nfc = {
+ .name = GPMI_NFC_DRIVER_NAME,
.id = 0,
.dev = {
.dma_mask = &common_dmamask,
@@ -175,6 +176,20 @@ static struct platform_device mxs_mmc[] = {
};
#endif
+#if defined(CONFIG_SPI_MXS) || defined(CONFIG_SPI_MXS_MODULE)
+static struct platform_device mxs_spi[] = {
+ {
+ .name = "mxs-spi",
+ .id = 0,
+ .dev = {
+ .dma_mask = &common_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .release = mxs_nop_release,
+ },
+ },
+};
+#endif
+
#if defined(CONFIG_MXS_WATCHDOG) || defined(CONFIG_MXS_WATCHDOG_MODULE)
static struct platform_device mxs_wdt = {
.name = "mxs-wdt",
@@ -195,6 +210,25 @@ static struct platform_device mxs_fec[] = {
.release = mxs_nop_release,
},
},
+ {
+ .name = "fec",
+ .id = 1,
+ .dev = {
+ .release = mxs_nop_release,
+ },
+ },
+};
+#endif
+
+#if defined(CONFIG_FEC_L2SWITCH)
+static struct platform_device mxs_l2switch[] = {
+ {
+ .name = "mxs-l2switch",
+ .id = 0,
+ .dev = {
+ .release = mxs_nop_release,
+ },
+ },
};
#endif
@@ -451,6 +485,16 @@ static struct platform_device mxs_persistent = {
};
#endif
+#ifdef CONFIG_FSL_OTP
+static struct platform_device otp_device = {
+ .name = "ocotp",
+ .id = 0,
+ .dev = {
+ .release = mxs_nop_release,
+ },
+};
+#endif
+
static inline void mxs_init_busfreq(void)
{
(void)platform_device_register(&busfreq_device);
@@ -482,12 +526,12 @@ static struct mxs_dev_lookup dev_lookup[] = {
},
#endif
-#if defined(CONFIG_MTD_NAND_GPMI1) || \
- defined(CONFIG_MTD_NAND_GPMI1_MODULE)
+#if defined(CONFIG_MTD_NAND_GPMI_NFC) || \
+ defined(CONFIG_MTD_NAND_GPMI_NFC_MODULE)
{
- .name = "gpmi",
+ .name = GPMI_NFC_DRIVER_NAME,
.size = 1,
- .pdev = &mxs_gpmi,
+ .pdev = &gpmi_nfc,
},
#endif
@@ -500,6 +544,14 @@ static struct mxs_dev_lookup dev_lookup[] = {
},
#endif
+#if defined(CONFIG_SPI_MXS) || defined(CONFIG_SPI_MXS_MODULE)
+ {
+ .name = "mxs-spi",
+ .size = ARRAY_SIZE(mxs_spi),
+ .pdev = mxs_spi,
+ },
+#endif
+
#if defined(CONFIG_MXS_WATCHDOG) || defined(CONFIG_MXS_WATCHDOG_MODULE)
{
.name = "mxs-wdt",
@@ -524,6 +576,14 @@ static struct mxs_dev_lookup dev_lookup[] = {
},
#endif
+#if defined(CONFIG_FSL_OTP)
+ {
+ .name = "ocotp",
+ .size = 1,
+ .pdev = &otp_device,
+ },
+#endif
+
#if defined(CONFIG_FB_MXS) || defined(CONFIG_FB_MXS_MODULE)
{
.name = "mxs-fb",
@@ -565,6 +625,14 @@ static struct mxs_dev_lookup dev_lookup[] = {
},
#endif
+#if defined(CONFIG_FEC_L2SWITCH)
+ {
+ .name = "mxs-l2switch",
+ .size = ARRAY_SIZE(mxs_l2switch),
+ .pdev = mxs_l2switch,
+ },
+#endif
+
#ifdef CONFIG_MXS_LRADC
{
.name = "mxs-lradc",
diff --git a/arch/arm/plat-mxs/dma-apbx.c b/arch/arm/plat-mxs/dma-apbx.c
index c27414f8c18d..6d77a6933d98 100644
--- a/arch/arm/plat-mxs/dma-apbx.c
+++ b/arch/arm/plat-mxs/dma-apbx.c
@@ -99,6 +99,9 @@ static void mxs_dma_apbx_info(struct mxs_dma_device *pdev,
reg = __raw_readl(pdev->base + HW_APBX_CTRL2);
info->status = reg >> chan;
info->buf_addr = __raw_readl(pdev->base + HW_APBX_CHn_BAR(chan));
+ reg = __raw_readl(pdev->base + HW_APBX_CHn_CMD(chan));
+ info->xfer_count = (reg & BM_APBX_CHn_CMD_XFER_COUNT) >> \
+ BP_APBX_CHn_CMD_XFER_COUNT;
}
static int
diff --git a/arch/arm/plat-mxs/dmaengine.c b/arch/arm/plat-mxs/dmaengine.c
index 453346e4057f..0c2485b18506 100644
--- a/arch/arm/plat-mxs/dmaengine.c
+++ b/arch/arm/plat-mxs/dmaengine.c
@@ -127,14 +127,16 @@ int mxs_dma_enable(int channel)
if (!(pchan->flags & MXS_DMA_FLAGS_ALLOCATED))
return -EINVAL;
+ /*
+ * neednot mutex lock, this function will be called in irq context.
+ * The mutex may cause process schedule.
+ */
pdma = pchan->dma;
- mutex_lock(&mxs_dma_mutex);
spin_lock_irqsave(&pchan->lock, flags);
if (pchan->pending_num && pdma->enable)
ret = pdma->enable(pchan, channel - pdma->chan_base);
pchan->flags |= MXS_DMA_FLAGS_BUSY;
spin_unlock_irqrestore(&pchan->lock, flags);
- mutex_unlock(&mxs_dma_mutex);
return ret;
}
EXPORT_SYMBOL(mxs_dma_enable);
@@ -151,17 +153,19 @@ void mxs_dma_disable(int channel)
return;
if (!(pchan->flags & MXS_DMA_FLAGS_BUSY))
return;
+ /*
+ * neednot mutex lock, this function will be called in irq context.
+ * The mutex may cause process schedule.
+ */
pdma = pchan->dma;
- mutex_lock(&mxs_dma_mutex);
spin_lock_irqsave(&pchan->lock, flags);
if (pdma->disable)
pdma->disable(pchan, channel - pdma->chan_base);
pchan->flags &= ~MXS_DMA_FLAGS_BUSY;
pchan->active_num = 0;
pchan->pending_num = 0;
- list_splice(&pchan->active, &pchan->done);
+ list_splice_init(&pchan->active, &pchan->done);
spin_unlock_irqrestore(&pchan->lock, flags);
- mutex_unlock(&mxs_dma_mutex);
}
EXPORT_SYMBOL(mxs_dma_disable);
diff --git a/arch/arm/plat-mxs/gpio.c b/arch/arm/plat-mxs/gpio.c
index f12d417b03e9..6c67c2bcfc5b 100644
--- a/arch/arm/plat-mxs/gpio.c
+++ b/arch/arm/plat-mxs/gpio.c
@@ -175,6 +175,8 @@ static struct irq_chip gpio_irq_chip = {
.ack = mxs_gpio_ack_irq,
.mask = mxs_gpio_mask_irq,
.unmask = mxs_gpio_unmask_irq,
+ .enable = mxs_gpio_unmask_irq,
+ .disable = mxs_gpio_mask_irq,
.set_type = mxs_gpio_set_irq_type,
};
diff --git a/arch/arm/plat-mxs/icoll.c b/arch/arm/plat-mxs/icoll.c
index bb4e4c12cb23..1e0b55bd26a9 100644
--- a/arch/arm/plat-mxs/icoll.c
+++ b/arch/arm/plat-mxs/icoll.c
@@ -56,10 +56,16 @@ static void icoll_unmask_irq(unsigned int irq)
g_icoll_base + HW_ICOLL_INTERRUPTn_SET(irq));
}
+static int icoll_set_wake_irq(unsigned int irq, unsigned int enabled)
+{
+ return 0;
+}
+
static struct irq_chip icoll_chip = {
.ack = icoll_ack_irq,
.mask = icoll_mask_irq,
.unmask = icoll_unmask_irq,
+ .set_wake = icoll_set_wake_irq,
};
void __init avic_init_irq(void __iomem *base, int nr_irqs)
diff --git a/arch/arm/plat-mxs/include/mach/bus_freq.h b/arch/arm/plat-mxs/include/mach/bus_freq.h
index a0254e84ca5c..0c41cd2205ff 100644
--- a/arch/arm/plat-mxs/include/mach/bus_freq.h
+++ b/arch/arm/plat-mxs/include/mach/bus_freq.h
@@ -33,13 +33,14 @@ struct profile {
int cur;
int vddio;
int vdda;
- int pll_off;
+ u16 xbus;
+ /* map of the upper 16 bits of HW_CLKCTRL_HBUS register */
+ u16 h_autoslow_flags;
};
-void hbus_auto_slow_mode_enable(void);
-void hbus_auto_slow_mode_disable(void);
-extern int cpu_clk_set_pll_on(struct clk *clk, unsigned int freq);
-extern int cpu_clk_set_pll_off(struct clk *clk, unsigned int freq);
+/* map of the upper 16 bits of HW_CLKCTRL_HBUS register */
+int is_hclk_autoslow_ok(void);
+
extern int timing_ctrl_rams(int ss);
#endif
diff --git a/arch/arm/plat-mxs/include/mach/clock.h b/arch/arm/plat-mxs/include/mach/clock.h
index 744a031b42b6..b506468976b5 100644
--- a/arch/arm/plat-mxs/include/mach/clock.h
+++ b/arch/arm/plat-mxs/include/mach/clock.h
@@ -30,11 +30,12 @@ struct clk {
struct clk *secondary;
unsigned long flags;
- __s8 ref;
+ int ref;
unsigned int scale_bits;
unsigned int enable_bits;
unsigned int bypass_bits;
unsigned int busy_bits;
+ unsigned int xtal_busy_bits;
unsigned int wait:1;
unsigned int invert:1;
@@ -71,16 +72,24 @@ struct clk {
void (*disable) (struct clk *);
/* Function ptr to set the parent clock of the clock. */
int (*set_parent) (struct clk *, struct clk *);
+
+ /* Function ptr to change the parent clock depending
+ * the system configuration at that time. Will only
+ * change the parent clock if the ref count is 0 (the clock
+ * is not being used)
+ */
+ int (*set_sys_dependent_parent) (struct clk *);
+
};
int clk_get_usecount(struct clk *clk);
extern int clk_register(struct clk_lookup *lookup);
extern void clk_unregister(struct clk_lookup *lookup);
-static inline int clk_is_busy(struct clk *clk)
-{
- return __raw_readl(clk->busy_reg) & (1 << clk->busy_bits);
-}
+bool clk_enable_h_autoslow(bool enable);
+void clk_set_h_autoslow_flags(u16 mask);
+void clk_en_public_h_asm_ctrl(bool (*enable_func)(bool),
+ void (*set_func)(u16));
struct mxs_emi_scaling_data {
u32 emi_div;
@@ -89,6 +98,8 @@ struct mxs_emi_scaling_data {
u32 new_freq;
};
+
+
#ifdef CONFIG_MXS_RAM_FREQ_SCALING
extern int mxs_ram_freq_scale(struct mxs_emi_scaling_data *);
extern u32 mxs_ram_funcs_sz;
diff --git a/arch/arm/plat-mxs/include/mach/device.h b/arch/arm/plat-mxs/include/mach/device.h
index 7a99647ed0ff..199ec1e62963 100644
--- a/arch/arm/plat-mxs/include/mach/device.h
+++ b/arch/arm/plat-mxs/include/mach/device.h
@@ -54,6 +54,12 @@ struct mxs_dma_plat_data {
unsigned int chan_num;
};
+struct fsl_otp_data {
+ char **fuse_name;
+ char *regulator_name;
+ unsigned int fuse_num;
+};
+
struct mxs_i2c_plat_data {
unsigned int pioqueue_mode:1;
};
@@ -119,6 +125,11 @@ struct mxs_mma7450_platform_data {
int int2;
};
+struct mxs_spi_platform_data {
+ int (*hw_pin_init)(void);
+ int (*hw_pin_release)(void);
+};
+
struct flexcan_platform_data {
char *core_reg;
char *io_reg;
@@ -169,57 +180,6 @@ struct mxs_audio_platform_data {
void *priv; /* used by board specific functions */
};
-/**
- * struct gpmi_platform_data - GPMI driver platform data.
- *
- * This structure communicates platform-specific information to the GPMI driver
- * that can't be expressed as resources.
- *
- * @io_uA: The current limit, in uA.
- * @min_prop_delay_in_ns: Minimum propagation delay of GPMI signals to and
- * from the NAND Flash device, in nanoseconds.
- * @max_prop_delay_in_ns: Maximum propagation delay of GPMI signals to and
- * from the NAND Flash device, in nanoseconds.
- * @pinmux_handler: A pointer to a function the driver will call to
- * request the pins it needs.
- * @boot_area_size_in_bytes: The amount of space reserved for use by the boot
- * ROM on the first and second chips. If this value is
- * zero, it indicates we're not reserving any space
- * for the boot area.
- * @partition_source_types: An array of strings that name sources of
- * partitioning information (e.g., the boot loader,
- * the kernel command line, etc.). The function
- * parse_mtd_partitions() recognizes these names and
- * applies the appropriate "plugins" to discover
- * partitioning information. If any is found, it will
- * be applied to the "general use" MTD (it will NOT
- * override the boot area protection mechanism).
- * @partitions: An optional pointer to an array of partition
- * descriptions. If the driver finds no partitioning
- * information elsewhere, it will apply these to the
- * "general use" MTD (they do NOT override the boot
- * area protection mechanism).
- * @partition_count: The number of elements in the partitions array.
- */
-
-struct gpmi_platform_data {
-
- int io_uA;
-
- unsigned min_prop_delay_in_ns;
- unsigned max_prop_delay_in_ns;
-
- int (*pinmux_handler)(void);
-
- uint32_t boot_area_size_in_bytes;
-
- const char **partition_source_types;
-
- struct mtd_partition *partitions;
- unsigned partition_count;
-
-};
-
struct mxs_persistent_bit_config {
int reg;
int start;
diff --git a/arch/arm/plat-mxs/include/mach/dmaengine.h b/arch/arm/plat-mxs/include/mach/dmaengine.h
index eecd260ac5b4..cdf6b1e32a43 100644
--- a/arch/arm/plat-mxs/include/mach/dmaengine.h
+++ b/arch/arm/plat-mxs/include/mach/dmaengine.h
@@ -106,6 +106,7 @@ struct mxs_dma_info {
#define MXS_DMA_INFO_ERR 0x00000001
#define MXS_DMA_INFO_ERR_STAT 0x00010000
unsigned int buf_addr;
+ unsigned int xfer_count;
};
/**
diff --git a/arch/arm/plat-mxs/include/mach/system.h b/arch/arm/plat-mxs/include/mach/system.h
index 63604de8d74a..faaa2ff3cf13 100644
--- a/arch/arm/plat-mxs/include/mach/system.h
+++ b/arch/arm/plat-mxs/include/mach/system.h
@@ -25,5 +25,6 @@ extern void arch_idle(void);
void arch_reset(char mode, const char *cmd);
extern void (*machine_arch_reset)(char mode, const char *cmd);
int mxs_reset_block(void __iomem *hwreg, int just_enable);
+int get_evk_board_version(void);
#endif /* __ASM_ARCH_SYSTEM_H__ */
diff --git a/arch/arm/plat-mxs/include/mach/timex.h b/arch/arm/plat-mxs/include/mach/timex.h
index 9db3d688223a..d622dda141f2 100644
--- a/arch/arm/plat-mxs/include/mach/timex.h
+++ b/arch/arm/plat-mxs/include/mach/timex.h
@@ -20,4 +20,4 @@
/*
* System time clock is sourced from the 32k clock
*/
-#define CLOCK_TICK_RATE 32768
+#define CLOCK_TICK_RATE 32000
diff --git a/arch/arm/plat-mxs/iram.c b/arch/arm/plat-mxs/iram.c
index 3d2a391bd2d1..c63b0a2a9a10 100644
--- a/arch/arm/plat-mxs/iram.c
+++ b/arch/arm/plat-mxs/iram.c
@@ -36,6 +36,11 @@ void *iram_alloc(unsigned int size, unsigned long *dma_addr)
*dma_addr = gen_pool_alloc(iram_pool, size);
pr_debug("iram alloc - %dB@0x%p\n", size, (void *)*dma_addr);
+
+ WARN_ON(!*dma_addr);
+ if (!*dma_addr)
+ return NULL;
+
return iram_phys_to_virt(*dma_addr);
}
EXPORT_SYMBOL(iram_alloc);
diff --git a/arch/arm/plat-mxs/timer-nomatch.c b/arch/arm/plat-mxs/timer-nomatch.c
index 66c488c99b42..db8906192f16 100644
--- a/arch/arm/plat-mxs/timer-nomatch.c
+++ b/arch/arm/plat-mxs/timer-nomatch.c
@@ -21,6 +21,7 @@
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/io.h>
+#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
@@ -119,9 +120,9 @@ void mxs_nomatch_timer_init(struct mxs_sys_timer *timer)
online_timer = timer;
- cksrc_mxs_nomatch.mult = clocksource_hz2mult(CLOCK_TICK_RATE,
+ cksrc_mxs_nomatch.mult = clocksource_hz2mult(clk_get_rate(timer->clk),
cksrc_mxs_nomatch.shift);
- ckevt_timrot.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
+ ckevt_timrot.mult = div_sc(clk_get_rate(timer->clk), NSEC_PER_SEC,
ckevt_timrot.shift);
ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot);
ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot);
@@ -145,7 +146,7 @@ void mxs_nomatch_timer_init(struct mxs_sys_timer *timer)
BM_TIMROT_TIMCTRLn_IRQ_EN,
online_timer->base + HW_TIMROT_TIMCTRLn(1));
- __raw_writel(CLOCK_TICK_RATE / HZ - 1,
+ __raw_writel(clk_get_rate(timer->clk) / HZ - 1,
online_timer->base + HW_TIMROT_TIMCOUNTn(0));
__raw_writel(0xFFFF, online_timer->base + HW_TIMROT_TIMCOUNTn(1));
@@ -181,7 +182,7 @@ void mxs_nomatch_resume_timer(void)
BM_TIMROT_TIMCTRLn_UPDATE |
BM_TIMROT_TIMCTRLn_IRQ_EN,
online_timer->base + HW_TIMROT_TIMCTRLn(1));
- __raw_writel(CLOCK_TICK_RATE / HZ - 1,
+ __raw_writel(clk_get_rate(online_timer->clk) / HZ - 1,
online_timer->base + HW_TIMROT_TIMCOUNTn(0));
__raw_writel(0xFFFF, online_timer->base + HW_TIMROT_TIMCOUNTn(1));
}
diff --git a/arch/arm/plat-mxs/usb_common.c b/arch/arm/plat-mxs/usb_common.c
index 5d8d0b6d9285..23134489472e 100644
--- a/arch/arm/plat-mxs/usb_common.c
+++ b/arch/arm/plat-mxs/usb_common.c
@@ -264,13 +264,16 @@ int usbotg_init(struct platform_device *pdev)
pdata->xcvr_type = xops->xcvr_type;
pdata->pdev = pdev;
- otg_used = 0;
if (!otg_used) {
pr_debug("%s: grab pins\n", __func__);
if (xops->init)
xops->init(xops);
usb_phy_enable(pdata);
}
+ /* Enable internal Phy clock */
+ tmp = __raw_readl(pdata->regs + UOG_PORTSC1);
+ tmp &= ~PORTSC_PHCD;
+ __raw_writel(tmp, pdata->regs + UOG_PORTSC1);
if (pdata->operating_mode == FSL_USB2_DR_HOST) {
/* enable FS/LS device */
@@ -288,11 +291,22 @@ EXPORT_SYMBOL(usbotg_init);
void usbotg_uninit(struct fsl_usb2_platform_data *pdata)
{
+ int tmp;
+ struct clk *usb_clk;
pr_debug("%s\n", __func__);
if (pdata->xcvr_ops && pdata->xcvr_ops->uninit)
pdata->xcvr_ops->uninit(pdata->xcvr_ops);
+ /* Disable internal Phy clock */
+ tmp = __raw_readl(pdata->regs + UOG_PORTSC1);
+ tmp |= PORTSC_PHCD;
+ __raw_writel(tmp, pdata->regs + UOG_PORTSC1);
+
+ usb_clk = clk_get(NULL, "usb_clk0");
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
+
pdata->regs = NULL;
otg_used--;
}
@@ -331,11 +345,16 @@ EXPORT_SYMBOL(fsl_usb_host_init);
void fsl_usb_host_uninit(struct fsl_usb2_platform_data *pdata)
{
+ struct clk *usb_clk;
pr_debug("%s\n", __func__);
if (pdata->xcvr_ops && pdata->xcvr_ops->uninit)
pdata->xcvr_ops->uninit(pdata->xcvr_ops);
+ usb_clk = clk_get(NULL, "usb_clk1");
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
+
pdata->regs = NULL;
}
EXPORT_SYMBOL(fsl_usb_host_uninit);
diff --git a/arch/arm/plat-mxs/utmixc.c b/arch/arm/plat-mxs/utmixc.c
index 1e9015d6de3f..8e842840e87a 100644
--- a/arch/arm/plat-mxs/utmixc.c
+++ b/arch/arm/plat-mxs/utmixc.c
@@ -45,7 +45,7 @@ static void set_vbus_draw(struct fsl_xcvr_ops *this,
{
#ifdef CONFIG_MXS_VBUS_CURRENT_DRAW
if ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL)
- & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x8000) {
+ & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x20000) {
printk(KERN_INFO "USB enumeration done,current limitation release\r\n");
__raw_writel(__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) |
BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT, REGS_POWER_BASE +
@@ -80,7 +80,7 @@ static void __exit utmixc_exit(void)
#ifdef CONFIG_MXS_VBUS_CURRENT_DRAW
fs_initcall(utmixc_init);
#else
- module_init(utmixc_init);
+ subsys_initcall(utmixc_init);
#endif
module_exit(utmixc_exit);
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index ebe0ea313658..817425c8e732 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1319,7 +1319,7 @@ mistral MACH_MISTRAL MISTRAL 1315
msm MACH_MSM MSM 1316
ct5910 MACH_CT5910 CT5910 1317
ct5912 MACH_CT5912 CT5912 1318
-hynet_ine MACH_HYNET_INE HYNET_INE 1319
+argonst_foundation MACH_HYNET_INE HYNET_INE 1319
hynet_app MACH_HYNET_APP HYNET_APP 1320
msm7200 MACH_MSM7200 MSM7200 1321
msm7600 MACH_MSM7600 MSM7600 1322
@@ -2257,7 +2257,7 @@ oratisalog MACH_ORATISALOG ORATISALOG 2268
oratismadi MACH_ORATISMADI ORATISMADI 2269
oratisot16 MACH_ORATISOT16 ORATISOT16 2270
oratisdesk MACH_ORATISDESK ORATISDESK 2271
-v2_ca9 MACH_V2P_CA9 V2P_CA9 2272
+vexpress MACH_VEXPRESS VEXPRESS 2272
sintexo MACH_SINTEXO SINTEXO 2273
cm3389 MACH_CM3389 CM3389 2274
omap3_cio MACH_OMAP3_CIO OMAP3_CIO 2275
@@ -2308,7 +2308,7 @@ ecac2378 MACH_ECAC2378 ECAC2378 2319
tazkiosk MACH_TAZKIOSK TAZKIOSK 2320
whiterabbit_mch MACH_WHITERABBIT_MCH WHITERABBIT_MCH 2321
sbox9263 MACH_SBOX9263 SBOX9263 2322
-oreo MACH_OREO OREO 2323
+oreo_camera MACH_OREO OREO 2323
smdk6442 MACH_SMDK6442 SMDK6442 2324
openrd_base MACH_OPENRD_BASE OPENRD_BASE 2325
incredible MACH_INCREDIBLE INCREDIBLE 2326
@@ -2498,7 +2498,7 @@ hiram MACH_HIRAM HIRAM 2510
phy3250 MACH_PHY3250 PHY3250 2511
ea3250 MACH_EA3250 EA3250 2512
fdi3250 MACH_FDI3250 FDI3250 2513
-whitestone MACH_WHITESTONE WHITESTONE 2514
+htcwhitestone MACH_WHITESTONE WHITESTONE 2514
at91sam9263nit MACH_AT91SAM9263NIT AT91SAM9263NIT 2515
ccmx51 MACH_CCMX51 CCMX51 2516
ccmx51js MACH_CCMX51JS CCMX51JS 2517
@@ -2594,4 +2594,7 @@ spacecom1 MACH_SPACECOM1 SPACECOM1 2604
pingu920 MACH_PINGU920 PINGU920 2605
bravoc MACH_BRAVOC BRAVOC 2606
cybo2440 MACH_CYBO2440 CYBO2440 2607
+mx50_arm2 MACH_MX50_ARM2 MX50_ARM2 2955
+mx50_rdp MACH_MX50_RDP MX50_RDP 2988
+
diff --git a/block/genhd.c b/block/genhd.c
index f4c64c2b303a..c0c7f38c7012 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -992,6 +992,22 @@ static void disk_release(struct device *dev)
free_part_stats(&disk->part0);
kfree(disk);
}
+
+static int disk_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct gendisk *disk = dev_to_disk(dev);
+ struct disk_part_iter piter;
+ struct hd_struct *part;
+ int cnt = 0;
+
+ disk_part_iter_init(&piter, disk, 0);
+ while((part = disk_part_iter_next(&piter)))
+ cnt++;
+ disk_part_iter_exit(&piter);
+ add_uevent_var(env, "NPARTS=%u", cnt);
+ return 0;
+}
+
struct class block_class = {
.name = "block",
};
@@ -1010,6 +1026,7 @@ static struct device_type disk_type = {
.groups = disk_attr_groups,
.release = disk_release,
.nodename = block_nodename,
+ .uevent = disk_uevent,
};
#ifdef CONFIG_PROC_FS
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 48bbdbe43e69..5dacbbd42483 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -90,6 +90,8 @@ source "drivers/memstick/Kconfig"
source "drivers/leds/Kconfig"
+source "drivers/switch/Kconfig"
+
source "drivers/accessibility/Kconfig"
source "drivers/infiniband/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 4a9a1c55b598..c19a0c18e5ed 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_ARCH_MXC) += mxc/
obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_MEMSTICK) += memstick/
obj-$(CONFIG_NEW_LEDS) += leds/
+obj-$(CONFIG_SWITCH) += switch/
obj-$(CONFIG_INFINIBAND) += infiniband/
obj-$(CONFIG_SGI_SN) += sn/
obj-y += firmware/
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index ae02b4114a6f..d7198890cdd3 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -55,6 +55,14 @@ config SATA_AHCI
If unsure, say N.
+config SATA_AHCI_PLATFORM
+ tristate "Platform AHCI SATA support"
+ help
+ This option enables support for Platform AHCI Serial ATA
+ controllers.
+
+ If unsure, say N.
+
config SATA_SIL24
tristate "Silicon Image 3124/3132 SATA support"
depends on PCI
@@ -72,6 +80,7 @@ config SATA_FSL
If unsure, say N.
+
config ATA_SFF
bool "ATA SFF support"
default y
@@ -759,6 +768,14 @@ config PATA_FSL
ATA interface.
If you are unsure, say N to this.
+config PATA_FSL_DISABLE_DMA
+ bool "Disable DMA on Freescale on-chip PATA devices"
+ depends on PATA_FSL
+ default y
+ help
+ Say yes to disable the Ultra DMA and Multi Word DMA transfers on
+ Freescale PATA SoC interface.
+
endif # ATA_SFF
endif # ATA
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index de9fda120642..69bcefa0df6b 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -1,7 +1,8 @@
obj-$(CONFIG_ATA) += libata.o
-obj-$(CONFIG_SATA_AHCI) += ahci.o
+obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o
+obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
obj-$(CONFIG_SATA_SVW) += sata_svw.o
obj-$(CONFIG_ATA_PIIX) += ata_piix.o
obj-$(CONFIG_SATA_PROMISE) += sata_promise.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index fe3eba5d6b3e..edc9b0ec9f39 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -45,64 +45,13 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
+#include "ahci.h"
#define DRV_NAME "ahci"
#define DRV_VERSION "3.0"
-/* Enclosure Management Control */
-#define EM_CTRL_MSG_TYPE 0x000f0000
-
-/* Enclosure Management LED Message Type */
-#define EM_MSG_LED_HBA_PORT 0x0000000f
-#define EM_MSG_LED_PMP_SLOT 0x0000ff00
-#define EM_MSG_LED_VALUE 0xffff0000
-#define EM_MSG_LED_VALUE_ACTIVITY 0x00070000
-#define EM_MSG_LED_VALUE_OFF 0xfff80000
-#define EM_MSG_LED_VALUE_ON 0x00010000
-
-static int ahci_skip_host_reset;
-static int ahci_ignore_sss;
-
-module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444);
-MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)");
-
-module_param_named(ignore_sss, ahci_ignore_sss, int, 0444);
-MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)");
-
-static int ahci_enable_alpm(struct ata_port *ap,
- enum link_pm policy);
-static void ahci_disable_alpm(struct ata_port *ap);
-static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
-static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
- size_t size);
-static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
- ssize_t size);
-
enum {
AHCI_PCI_BAR = 5,
- AHCI_MAX_PORTS = 32,
- AHCI_MAX_SG = 168, /* hardware max is 64K */
- AHCI_DMA_BOUNDARY = 0xffffffff,
- AHCI_MAX_CMDS = 32,
- AHCI_CMD_SZ = 32,
- AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ,
- AHCI_RX_FIS_SZ = 256,
- AHCI_CMD_TBL_CDB = 0x40,
- AHCI_CMD_TBL_HDR_SZ = 0x80,
- AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
- AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
- AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
- AHCI_RX_FIS_SZ,
- AHCI_IRQ_ON_SG = (1 << 31),
- AHCI_CMD_ATAPI = (1 << 5),
- AHCI_CMD_WRITE = (1 << 6),
- AHCI_CMD_PREFETCH = (1 << 7),
- AHCI_CMD_RESET = (1 << 8),
- AHCI_CMD_CLR_BUSY = (1 << 10),
-
- RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
- RX_FIS_SDB = 0x58, /* offset of SDB FIS data */
- RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
board_ahci = 0,
board_ahci_vt8251 = 1,
@@ -113,280 +62,20 @@ enum {
board_ahci_mcp65 = 6,
board_ahci_nopmp = 7,
board_ahci_yesncq = 8,
-
- /* global controller registers */
- HOST_CAP = 0x00, /* host capabilities */
- HOST_CTL = 0x04, /* global host control */
- HOST_IRQ_STAT = 0x08, /* interrupt status */
- HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */
- HOST_VERSION = 0x10, /* AHCI spec. version compliancy */
- HOST_EM_LOC = 0x1c, /* Enclosure Management location */
- HOST_EM_CTL = 0x20, /* Enclosure Management Control */
-
- /* HOST_CTL bits */
- HOST_RESET = (1 << 0), /* reset controller; self-clear */
- HOST_IRQ_EN = (1 << 1), /* global IRQ enable */
- HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
-
- /* HOST_CAP bits */
- HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */
- HOST_CAP_SSC = (1 << 14), /* Slumber capable */
- HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */
- HOST_CAP_CLO = (1 << 24), /* Command List Override support */
- HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */
- HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
- HOST_CAP_SNTF = (1 << 29), /* SNotification register */
- HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
- HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
-
- /* registers for each SATA port */
- PORT_LST_ADDR = 0x00, /* command list DMA addr */
- PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */
- PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */
- PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */
- PORT_IRQ_STAT = 0x10, /* interrupt status */
- PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */
- PORT_CMD = 0x18, /* port command */
- PORT_TFDATA = 0x20, /* taskfile data */
- PORT_SIG = 0x24, /* device TF signature */
- PORT_CMD_ISSUE = 0x38, /* command issue */
- PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */
- PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */
- PORT_SCR_ERR = 0x30, /* SATA phy register: SError */
- PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */
- PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */
-
- /* PORT_IRQ_{STAT,MASK} bits */
- PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
- PORT_IRQ_TF_ERR = (1 << 30), /* task file error */
- PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */
- PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */
- PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */
- PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */
- PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */
- PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */
-
- PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */
- PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */
- PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */
- PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */
- PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */
- PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */
- PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */
- PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */
- PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */
-
- PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR |
- PORT_IRQ_IF_ERR |
- PORT_IRQ_CONNECT |
- PORT_IRQ_PHYRDY |
- PORT_IRQ_UNK_FIS |
- PORT_IRQ_BAD_PMP,
- PORT_IRQ_ERROR = PORT_IRQ_FREEZE |
- PORT_IRQ_TF_ERR |
- PORT_IRQ_HBUS_DATA_ERR,
- DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
- PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
- PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
-
- /* PORT_CMD bits */
- PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */
- PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */
- PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
- PORT_CMD_PMP = (1 << 17), /* PMP attached */
- PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
- PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
- PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */
- PORT_CMD_CLO = (1 << 3), /* Command list override */
- PORT_CMD_POWER_ON = (1 << 2), /* Power up device */
- PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */
- PORT_CMD_START = (1 << 0), /* Enable port DMA engine */
-
- PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */
- PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */
- PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
- PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
-
- /* hpriv->flags bits */
- AHCI_HFLAG_NO_NCQ = (1 << 0),
- AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */
- AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */
- AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */
- AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */
- AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */
- AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */
- AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */
- AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */
- AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */
- AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */
- AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = (1 << 11), /* treat SRST timeout as
- link offline */
-
- /* ap->flags bits */
-
- AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
- ATA_FLAG_IPM,
-
- ICH_MAP = 0x90, /* ICH MAP register */
-
- /* em constants */
- EM_MAX_SLOTS = 8,
- EM_MAX_RETRY = 5,
-
- /* em_ctl bits */
- EM_CTL_RST = (1 << 9), /* Reset */
- EM_CTL_TM = (1 << 8), /* Transmit Message */
- EM_CTL_ALHD = (1 << 26), /* Activity LED */
-};
-
-struct ahci_cmd_hdr {
- __le32 opts;
- __le32 status;
- __le32 tbl_addr;
- __le32 tbl_addr_hi;
- __le32 reserved[4];
-};
-
-struct ahci_sg {
- __le32 addr;
- __le32 addr_hi;
- __le32 reserved;
- __le32 flags_size;
+ board_ahci_nosntf = 9,
};
-struct ahci_em_priv {
- enum sw_activity blink_policy;
- struct timer_list timer;
- unsigned long saved_activity;
- unsigned long activity;
- unsigned long led_state;
-};
-
-struct ahci_host_priv {
- unsigned int flags; /* AHCI_HFLAG_* */
- u32 cap; /* cap to use */
- u32 port_map; /* port map to use */
- u32 saved_cap; /* saved initial cap */
- u32 saved_port_map; /* saved initial port_map */
- u32 em_loc; /* enclosure management location */
-};
-
-struct ahci_port_priv {
- struct ata_link *active_link;
- struct ahci_cmd_hdr *cmd_slot;
- dma_addr_t cmd_slot_dma;
- void *cmd_tbl;
- dma_addr_t cmd_tbl_dma;
- void *rx_fis;
- dma_addr_t rx_fis_dma;
- /* for NCQ spurious interrupt analysis */
- unsigned int ncq_saw_d2h:1;
- unsigned int ncq_saw_dmas:1;
- unsigned int ncq_saw_sdb:1;
- u32 intr_mask; /* interrupts to enable */
- /* enclosure management info per PM slot */
- struct ahci_em_priv em_priv[EM_MAX_SLOTS];
-};
-
-static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
-static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
-static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
-static int ahci_port_start(struct ata_port *ap);
-static void ahci_port_stop(struct ata_port *ap);
-static void ahci_qc_prep(struct ata_queued_cmd *qc);
-static void ahci_freeze(struct ata_port *ap);
-static void ahci_thaw(struct ata_port *ap);
-static void ahci_pmp_attach(struct ata_port *ap);
-static void ahci_pmp_detach(struct ata_port *ap);
-static int ahci_softreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline);
static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
-static int ahci_hardreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline);
static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
-static void ahci_postreset(struct ata_link *link, unsigned int *class);
-static void ahci_error_handler(struct ata_port *ap);
-static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
-static int ahci_port_resume(struct ata_port *ap);
-static void ahci_dev_config(struct ata_device *dev);
-static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
- u32 opts);
#ifdef CONFIG_PM
-static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
static int ahci_pci_device_resume(struct pci_dev *pdev);
#endif
-static ssize_t ahci_activity_show(struct ata_device *dev, char *buf);
-static ssize_t ahci_activity_store(struct ata_device *dev,
- enum sw_activity val);
-static void ahci_init_sw_activity(struct ata_link *link);
-
-static struct device_attribute *ahci_shost_attrs[] = {
- &dev_attr_link_power_management_policy,
- &dev_attr_em_message_type,
- &dev_attr_em_message,
- NULL
-};
-
-static struct device_attribute *ahci_sdev_attrs[] = {
- &dev_attr_sw_activity,
- &dev_attr_unload_heads,
- NULL
-};
-
-static struct scsi_host_template ahci_sht = {
- ATA_NCQ_SHT(DRV_NAME),
- .can_queue = AHCI_MAX_CMDS - 1,
- .sg_tablesize = AHCI_MAX_SG,
- .dma_boundary = AHCI_DMA_BOUNDARY,
- .shost_attrs = ahci_shost_attrs,
- .sdev_attrs = ahci_sdev_attrs,
-};
-
-static struct ata_port_operations ahci_ops = {
- .inherits = &sata_pmp_port_ops,
-
- .qc_defer = sata_pmp_qc_defer_cmd_switch,
- .qc_prep = ahci_qc_prep,
- .qc_issue = ahci_qc_issue,
- .qc_fill_rtf = ahci_qc_fill_rtf,
-
- .freeze = ahci_freeze,
- .thaw = ahci_thaw,
- .softreset = ahci_softreset,
- .hardreset = ahci_hardreset,
- .postreset = ahci_postreset,
- .pmp_softreset = ahci_softreset,
- .error_handler = ahci_error_handler,
- .post_internal_cmd = ahci_post_internal_cmd,
- .dev_config = ahci_dev_config,
-
- .scr_read = ahci_scr_read,
- .scr_write = ahci_scr_write,
- .pmp_attach = ahci_pmp_attach,
- .pmp_detach = ahci_pmp_detach,
-
- .enable_pm = ahci_enable_alpm,
- .disable_pm = ahci_disable_alpm,
- .em_show = ahci_led_show,
- .em_store = ahci_led_store,
- .sw_activity_show = ahci_activity_show,
- .sw_activity_store = ahci_activity_store,
-#ifdef CONFIG_PM
- .port_suspend = ahci_port_suspend,
- .port_resume = ahci_port_resume,
-#endif
- .port_start = ahci_port_start,
- .port_stop = ahci_port_stop,
-};
static struct ata_port_operations ahci_vt8251_ops = {
.inherits = &ahci_ops,
@@ -473,7 +162,7 @@ static const struct ata_port_info ahci_port_info[] = {
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
- /* board_ahci_yesncq */
+ [board_ahci_yesncq] =
{
AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ),
.flags = AHCI_FLAG_COMMON,
@@ -481,6 +170,14 @@ static const struct ata_port_info ahci_port_info[] = {
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
+ [board_ahci_nosntf] =
+ {
+ AHCI_HFLAGS (AHCI_HFLAG_NO_SNTF),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+ },
};
static const struct pci_device_id ahci_pci_tbl[] = {
@@ -496,7 +193,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2822), board_ahci_nosntf }, /* ICH8 */
{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
@@ -644,12 +341,6 @@ static struct pci_driver ahci_pci_driver = {
#endif
};
-static int ahci_em_messages = 1;
-module_param(ahci_em_messages, int, 0444);
-/* add other LED protocol types when they become supported */
-MODULE_PARM_DESC(ahci_em_messages,
- "Set AHCI Enclosure Management Message type (0 = disabled, 1 = LED");
-
#if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
static int marvell_enable;
#else
@@ -659,112 +350,15 @@ module_param(marvell_enable, int, 0644);
MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)");
-static inline int ahci_nr_ports(u32 cap)
-{
- return (cap & 0x1f) + 1;
-}
-
-static inline void __iomem *__ahci_port_base(struct ata_host *host,
- unsigned int port_no)
-{
- void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
-
- return mmio + 0x100 + (port_no * 0x80);
-}
-
-static inline void __iomem *ahci_port_base(struct ata_port *ap)
-{
- return __ahci_port_base(ap->host, ap->port_no);
-}
-
-static void ahci_enable_ahci(void __iomem *mmio)
-{
- int i;
- u32 tmp;
-
- /* turn on AHCI_EN */
- tmp = readl(mmio + HOST_CTL);
- if (tmp & HOST_AHCI_EN)
- return;
-
- /* Some controllers need AHCI_EN to be written multiple times.
- * Try a few times before giving up.
- */
- for (i = 0; i < 5; i++) {
- tmp |= HOST_AHCI_EN;
- writel(tmp, mmio + HOST_CTL);
- tmp = readl(mmio + HOST_CTL); /* flush && sanity check */
- if (tmp & HOST_AHCI_EN)
- return;
- msleep(10);
- }
-
- WARN_ON(1);
-}
-
-/**
- * ahci_save_initial_config - Save and fixup initial config values
- * @pdev: target PCI device
- * @hpriv: host private area to store config values
- *
- * Some registers containing configuration info might be setup by
- * BIOS and might be cleared on reset. This function saves the
- * initial values of those registers into @hpriv such that they
- * can be restored after controller reset.
- *
- * If inconsistent, config values are fixed up by this function.
- *
- * LOCKING:
- * None.
- */
-static void ahci_save_initial_config(struct pci_dev *pdev,
- struct ahci_host_priv *hpriv)
+static void ahci_pci_save_initial_config(struct pci_dev *pdev,
+ struct ahci_host_priv *hpriv)
{
- void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
- u32 cap, port_map;
- int i;
- int mv;
-
- /* make sure AHCI mode is enabled before accessing CAP */
- ahci_enable_ahci(mmio);
+ unsigned int force_port_map = 0;
+ unsigned int mask_port_map = 0;
- /* Values prefixed with saved_ are written back to host after
- * reset. Values without are used for driver operation.
- */
- hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
- hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
-
- /* some chips have errata preventing 64bit use */
- if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
- dev_printk(KERN_INFO, &pdev->dev,
- "controller can't do 64bit DMA, forcing 32bit\n");
- cap &= ~HOST_CAP_64;
- }
-
- if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
- dev_printk(KERN_INFO, &pdev->dev,
- "controller can't do NCQ, turning off CAP_NCQ\n");
- cap &= ~HOST_CAP_NCQ;
- }
-
- if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) {
- dev_printk(KERN_INFO, &pdev->dev,
- "controller can do NCQ, turning on CAP_NCQ\n");
- cap |= HOST_CAP_NCQ;
- }
-
- if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
- dev_printk(KERN_INFO, &pdev->dev,
- "controller can't do PMP, turning off CAP_PMP\n");
- cap &= ~HOST_CAP_PMP;
- }
-
- if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 &&
- port_map != 1) {
- dev_printk(KERN_INFO, &pdev->dev,
- "JMB361 has only one port, port_map 0x%x -> 0x%x\n",
- port_map, 1);
- port_map = 1;
+ if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) {
+ dev_info(&pdev->dev, "JMB361 has only one port\n");
+ force_port_map = 1;
}
/*
@@ -774,466 +368,25 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
*/
if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
if (pdev->device == 0x6121)
- mv = 0x3;
+ mask_port_map = 0x3;
else
- mv = 0xf;
- dev_printk(KERN_ERR, &pdev->dev,
- "MV_AHCI HACK: port_map %x -> %x\n",
- port_map,
- port_map & mv);
- dev_printk(KERN_ERR, &pdev->dev,
+ mask_port_map = 0xf;
+ dev_info(&pdev->dev,
"Disabling your PATA port. Use the boot option 'ahci.marvell_enable=0' to avoid this.\n");
-
- port_map &= mv;
- }
-
- /* cross check port_map and cap.n_ports */
- if (port_map) {
- int map_ports = 0;
-
- for (i = 0; i < AHCI_MAX_PORTS; i++)
- if (port_map & (1 << i))
- map_ports++;
-
- /* If PI has more ports than n_ports, whine, clear
- * port_map and let it be generated from n_ports.
- */
- if (map_ports > ahci_nr_ports(cap)) {
- dev_printk(KERN_WARNING, &pdev->dev,
- "implemented port map (0x%x) contains more "
- "ports than nr_ports (%u), using nr_ports\n",
- port_map, ahci_nr_ports(cap));
- port_map = 0;
- }
- }
-
- /* fabricate port_map from cap.nr_ports */
- if (!port_map) {
- port_map = (1 << ahci_nr_ports(cap)) - 1;
- dev_printk(KERN_WARNING, &pdev->dev,
- "forcing PORTS_IMPL to 0x%x\n", port_map);
-
- /* write the fixed up value to the PI register */
- hpriv->saved_port_map = port_map;
- }
-
- /* record values to use during operation */
- hpriv->cap = cap;
- hpriv->port_map = port_map;
-}
-
-/**
- * ahci_restore_initial_config - Restore initial config
- * @host: target ATA host
- *
- * Restore initial config stored by ahci_save_initial_config().
- *
- * LOCKING:
- * None.
- */
-static void ahci_restore_initial_config(struct ata_host *host)
-{
- struct ahci_host_priv *hpriv = host->private_data;
- void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
-
- writel(hpriv->saved_cap, mmio + HOST_CAP);
- writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
- (void) readl(mmio + HOST_PORTS_IMPL); /* flush */
-}
-
-static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
-{
- static const int offset[] = {
- [SCR_STATUS] = PORT_SCR_STAT,
- [SCR_CONTROL] = PORT_SCR_CTL,
- [SCR_ERROR] = PORT_SCR_ERR,
- [SCR_ACTIVE] = PORT_SCR_ACT,
- [SCR_NOTIFICATION] = PORT_SCR_NTF,
- };
- struct ahci_host_priv *hpriv = ap->host->private_data;
-
- if (sc_reg < ARRAY_SIZE(offset) &&
- (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
- return offset[sc_reg];
- return 0;
-}
-
-static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
-{
- void __iomem *port_mmio = ahci_port_base(link->ap);
- int offset = ahci_scr_offset(link->ap, sc_reg);
-
- if (offset) {
- *val = readl(port_mmio + offset);
- return 0;
- }
- return -EINVAL;
-}
-
-static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
-{
- void __iomem *port_mmio = ahci_port_base(link->ap);
- int offset = ahci_scr_offset(link->ap, sc_reg);
-
- if (offset) {
- writel(val, port_mmio + offset);
- return 0;
- }
- return -EINVAL;
-}
-
-static void ahci_start_engine(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 tmp;
-
- /* start DMA */
- tmp = readl(port_mmio + PORT_CMD);
- tmp |= PORT_CMD_START;
- writel(tmp, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
-}
-
-static int ahci_stop_engine(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 tmp;
-
- tmp = readl(port_mmio + PORT_CMD);
-
- /* check if the HBA is idle */
- if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
- return 0;
-
- /* setting HBA to idle */
- tmp &= ~PORT_CMD_START;
- writel(tmp, port_mmio + PORT_CMD);
-
- /* wait for engine to stop. This could be as long as 500 msec */
- tmp = ata_wait_register(port_mmio + PORT_CMD,
- PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
- if (tmp & PORT_CMD_LIST_ON)
- return -EIO;
-
- return 0;
-}
-
-static void ahci_start_fis_rx(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ahci_host_priv *hpriv = ap->host->private_data;
- struct ahci_port_priv *pp = ap->private_data;
- u32 tmp;
-
- /* set FIS registers */
- if (hpriv->cap & HOST_CAP_64)
- writel((pp->cmd_slot_dma >> 16) >> 16,
- port_mmio + PORT_LST_ADDR_HI);
- writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
-
- if (hpriv->cap & HOST_CAP_64)
- writel((pp->rx_fis_dma >> 16) >> 16,
- port_mmio + PORT_FIS_ADDR_HI);
- writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
-
- /* enable FIS reception */
- tmp = readl(port_mmio + PORT_CMD);
- tmp |= PORT_CMD_FIS_RX;
- writel(tmp, port_mmio + PORT_CMD);
-
- /* flush */
- readl(port_mmio + PORT_CMD);
-}
-
-static int ahci_stop_fis_rx(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 tmp;
-
- /* disable FIS reception */
- tmp = readl(port_mmio + PORT_CMD);
- tmp &= ~PORT_CMD_FIS_RX;
- writel(tmp, port_mmio + PORT_CMD);
-
- /* wait for completion, spec says 500ms, give it 1000 */
- tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
- PORT_CMD_FIS_ON, 10, 1000);
- if (tmp & PORT_CMD_FIS_ON)
- return -EBUSY;
-
- return 0;
-}
-
-static void ahci_power_up(struct ata_port *ap)
-{
- struct ahci_host_priv *hpriv = ap->host->private_data;
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 cmd;
-
- cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
-
- /* spin up device */
- if (hpriv->cap & HOST_CAP_SSS) {
- cmd |= PORT_CMD_SPIN_UP;
- writel(cmd, port_mmio + PORT_CMD);
- }
-
- /* wake up link */
- writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
-}
-
-static void ahci_disable_alpm(struct ata_port *ap)
-{
- struct ahci_host_priv *hpriv = ap->host->private_data;
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 cmd;
- struct ahci_port_priv *pp = ap->private_data;
-
- /* IPM bits should be disabled by libata-core */
- /* get the existing command bits */
- cmd = readl(port_mmio + PORT_CMD);
-
- /* disable ALPM and ASP */
- cmd &= ~PORT_CMD_ASP;
- cmd &= ~PORT_CMD_ALPE;
-
- /* force the interface back to active */
- cmd |= PORT_CMD_ICC_ACTIVE;
-
- /* write out new cmd value */
- writel(cmd, port_mmio + PORT_CMD);
- cmd = readl(port_mmio + PORT_CMD);
-
- /* wait 10ms to be sure we've come out of any low power state */
- msleep(10);
-
- /* clear out any PhyRdy stuff from interrupt status */
- writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
-
- /* go ahead and clean out PhyRdy Change from Serror too */
- ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
-
- /*
- * Clear flag to indicate that we should ignore all PhyRdy
- * state changes
- */
- hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG;
-
- /*
- * Enable interrupts on Phy Ready.
- */
- pp->intr_mask |= PORT_IRQ_PHYRDY;
- writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
-
- /*
- * don't change the link pm policy - we can be called
- * just to turn of link pm temporarily
- */
-}
-
-static int ahci_enable_alpm(struct ata_port *ap,
- enum link_pm policy)
-{
- struct ahci_host_priv *hpriv = ap->host->private_data;
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 cmd;
- struct ahci_port_priv *pp = ap->private_data;
- u32 asp;
-
- /* Make sure the host is capable of link power management */
- if (!(hpriv->cap & HOST_CAP_ALPM))
- return -EINVAL;
-
- switch (policy) {
- case MAX_PERFORMANCE:
- case NOT_AVAILABLE:
- /*
- * if we came here with NOT_AVAILABLE,
- * it just means this is the first time we
- * have tried to enable - default to max performance,
- * and let the user go to lower power modes on request.
- */
- ahci_disable_alpm(ap);
- return 0;
- case MIN_POWER:
- /* configure HBA to enter SLUMBER */
- asp = PORT_CMD_ASP;
- break;
- case MEDIUM_POWER:
- /* configure HBA to enter PARTIAL */
- asp = 0;
- break;
- default:
- return -EINVAL;
- }
-
- /*
- * Disable interrupts on Phy Ready. This keeps us from
- * getting woken up due to spurious phy ready interrupts
- * TBD - Hot plug should be done via polling now, is
- * that even supported?
- */
- pp->intr_mask &= ~PORT_IRQ_PHYRDY;
- writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
-
- /*
- * Set a flag to indicate that we should ignore all PhyRdy
- * state changes since these can happen now whenever we
- * change link state
- */
- hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG;
-
- /* get the existing command bits */
- cmd = readl(port_mmio + PORT_CMD);
-
- /*
- * Set ASP based on Policy
- */
- cmd |= asp;
-
- /*
- * Setting this bit will instruct the HBA to aggressively
- * enter a lower power link state when it's appropriate and
- * based on the value set above for ASP
- */
- cmd |= PORT_CMD_ALPE;
-
- /* write out new cmd value */
- writel(cmd, port_mmio + PORT_CMD);
- cmd = readl(port_mmio + PORT_CMD);
-
- /* IPM bits should be set by libata-core */
- return 0;
-}
-
-#ifdef CONFIG_PM
-static void ahci_power_down(struct ata_port *ap)
-{
- struct ahci_host_priv *hpriv = ap->host->private_data;
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 cmd, scontrol;
-
- if (!(hpriv->cap & HOST_CAP_SSS))
- return;
-
- /* put device into listen mode, first set PxSCTL.DET to 0 */
- scontrol = readl(port_mmio + PORT_SCR_CTL);
- scontrol &= ~0xf;
- writel(scontrol, port_mmio + PORT_SCR_CTL);
-
- /* then set PxCMD.SUD to 0 */
- cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
- cmd &= ~PORT_CMD_SPIN_UP;
- writel(cmd, port_mmio + PORT_CMD);
-}
-#endif
-
-static void ahci_start_port(struct ata_port *ap)
-{
- struct ahci_port_priv *pp = ap->private_data;
- struct ata_link *link;
- struct ahci_em_priv *emp;
- ssize_t rc;
- int i;
-
- /* enable FIS reception */
- ahci_start_fis_rx(ap);
-
- /* enable DMA */
- ahci_start_engine(ap);
-
- /* turn on LEDs */
- if (ap->flags & ATA_FLAG_EM) {
- ata_for_each_link(link, ap, EDGE) {
- emp = &pp->em_priv[link->pmp];
-
- /* EM Transmit bit maybe busy during init */
- for (i = 0; i < EM_MAX_RETRY; i++) {
- rc = ahci_transmit_led_message(ap,
- emp->led_state,
- 4);
- if (rc == -EBUSY)
- msleep(1);
- else
- break;
- }
- }
- }
-
- if (ap->flags & ATA_FLAG_SW_ACTIVITY)
- ata_for_each_link(link, ap, EDGE)
- ahci_init_sw_activity(link);
-
-}
-
-static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
-{
- int rc;
-
- /* disable DMA */
- rc = ahci_stop_engine(ap);
- if (rc) {
- *emsg = "failed to stop engine";
- return rc;
- }
-
- /* disable FIS reception */
- rc = ahci_stop_fis_rx(ap);
- if (rc) {
- *emsg = "failed stop FIS RX";
- return rc;
}
- return 0;
+ ahci_save_initial_config(&pdev->dev, hpriv, force_port_map,
+ mask_port_map);
}
-static int ahci_reset_controller(struct ata_host *host)
+static int ahci_pci_reset_controller(struct ata_host *host)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
- struct ahci_host_priv *hpriv = host->private_data;
- void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
- u32 tmp;
- /* we must be in AHCI mode, before using anything
- * AHCI-specific, such as HOST_RESET.
- */
- ahci_enable_ahci(mmio);
-
- /* global controller reset */
- if (!ahci_skip_host_reset) {
- tmp = readl(mmio + HOST_CTL);
- if ((tmp & HOST_RESET) == 0) {
- writel(tmp | HOST_RESET, mmio + HOST_CTL);
- readl(mmio + HOST_CTL); /* flush */
- }
-
- /*
- * to perform host reset, OS should set HOST_RESET
- * and poll until this bit is read to be "0".
- * reset must complete within 1 second, or
- * the hardware should be considered fried.
- */
- tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET,
- HOST_RESET, 10, 1000);
-
- if (tmp & HOST_RESET) {
- dev_printk(KERN_ERR, host->dev,
- "controller reset failed (0x%x)\n", tmp);
- return -EIO;
- }
-
- /* turn on AHCI mode */
- ahci_enable_ahci(mmio);
-
- /* Some registers might be cleared on reset. Restore
- * initial values.
- */
- ahci_restore_initial_config(host);
- } else
- dev_printk(KERN_INFO, host->dev,
- "skipping global host reset\n");
+ ahci_reset_controller(host);
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+ struct ahci_host_priv *hpriv = host->private_data;
u16 tmp16;
/* configure PCS */
@@ -1247,267 +400,10 @@ static int ahci_reset_controller(struct ata_host *host)
return 0;
}
-static void ahci_sw_activity(struct ata_link *link)
-{
- struct ata_port *ap = link->ap;
- struct ahci_port_priv *pp = ap->private_data;
- struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
-
- if (!(link->flags & ATA_LFLAG_SW_ACTIVITY))
- return;
-
- emp->activity++;
- if (!timer_pending(&emp->timer))
- mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10));
-}
-
-static void ahci_sw_activity_blink(unsigned long arg)
-{
- struct ata_link *link = (struct ata_link *)arg;
- struct ata_port *ap = link->ap;
- struct ahci_port_priv *pp = ap->private_data;
- struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
- unsigned long led_message = emp->led_state;
- u32 activity_led_state;
- unsigned long flags;
-
- led_message &= EM_MSG_LED_VALUE;
- led_message |= ap->port_no | (link->pmp << 8);
-
- /* check to see if we've had activity. If so,
- * toggle state of LED and reset timer. If not,
- * turn LED to desired idle state.
- */
- spin_lock_irqsave(ap->lock, flags);
- if (emp->saved_activity != emp->activity) {
- emp->saved_activity = emp->activity;
- /* get the current LED state */
- activity_led_state = led_message & EM_MSG_LED_VALUE_ON;
-
- if (activity_led_state)
- activity_led_state = 0;
- else
- activity_led_state = 1;
-
- /* clear old state */
- led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
-
- /* toggle state */
- led_message |= (activity_led_state << 16);
- mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100));
- } else {
- /* switch to idle */
- led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
- if (emp->blink_policy == BLINK_OFF)
- led_message |= (1 << 16);
- }
- spin_unlock_irqrestore(ap->lock, flags);
- ahci_transmit_led_message(ap, led_message, 4);
-}
-
-static void ahci_init_sw_activity(struct ata_link *link)
-{
- struct ata_port *ap = link->ap;
- struct ahci_port_priv *pp = ap->private_data;
- struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
-
- /* init activity stats, setup timer */
- emp->saved_activity = emp->activity = 0;
- setup_timer(&emp->timer, ahci_sw_activity_blink, (unsigned long)link);
-
- /* check our blink policy and set flag for link if it's enabled */
- if (emp->blink_policy)
- link->flags |= ATA_LFLAG_SW_ACTIVITY;
-}
-
-static int ahci_reset_em(struct ata_host *host)
-{
- void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
- u32 em_ctl;
-
- em_ctl = readl(mmio + HOST_EM_CTL);
- if ((em_ctl & EM_CTL_TM) || (em_ctl & EM_CTL_RST))
- return -EINVAL;
-
- writel(em_ctl | EM_CTL_RST, mmio + HOST_EM_CTL);
- return 0;
-}
-
-static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
- ssize_t size)
-{
- struct ahci_host_priv *hpriv = ap->host->private_data;
- struct ahci_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- u32 em_ctl;
- u32 message[] = {0, 0};
- unsigned long flags;
- int pmp;
- struct ahci_em_priv *emp;
-
- /* get the slot number from the message */
- pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
- if (pmp < EM_MAX_SLOTS)
- emp = &pp->em_priv[pmp];
- else
- return -EINVAL;
-
- spin_lock_irqsave(ap->lock, flags);
-
- /*
- * if we are still busy transmitting a previous message,
- * do not allow
- */
- em_ctl = readl(mmio + HOST_EM_CTL);
- if (em_ctl & EM_CTL_TM) {
- spin_unlock_irqrestore(ap->lock, flags);
- return -EBUSY;
- }
-
- /*
- * create message header - this is all zero except for
- * the message size, which is 4 bytes.
- */
- message[0] |= (4 << 8);
-
- /* ignore 0:4 of byte zero, fill in port info yourself */
- message[1] = ((state & ~EM_MSG_LED_HBA_PORT) | ap->port_no);
-
- /* write message to EM_LOC */
- writel(message[0], mmio + hpriv->em_loc);
- writel(message[1], mmio + hpriv->em_loc+4);
-
- /* save off new led state for port/slot */
- emp->led_state = state;
-
- /*
- * tell hardware to transmit the message
- */
- writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
-
- spin_unlock_irqrestore(ap->lock, flags);
- return size;
-}
-
-static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
-{
- struct ahci_port_priv *pp = ap->private_data;
- struct ata_link *link;
- struct ahci_em_priv *emp;
- int rc = 0;
-
- ata_for_each_link(link, ap, EDGE) {
- emp = &pp->em_priv[link->pmp];
- rc += sprintf(buf, "%lx\n", emp->led_state);
- }
- return rc;
-}
-
-static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
- size_t size)
-{
- int state;
- int pmp;
- struct ahci_port_priv *pp = ap->private_data;
- struct ahci_em_priv *emp;
-
- state = simple_strtoul(buf, NULL, 0);
-
- /* get the slot number from the message */
- pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
- if (pmp < EM_MAX_SLOTS)
- emp = &pp->em_priv[pmp];
- else
- return -EINVAL;
-
- /* mask off the activity bits if we are in sw_activity
- * mode, user should turn off sw_activity before setting
- * activity led through em_message
- */
- if (emp->blink_policy)
- state &= ~EM_MSG_LED_VALUE_ACTIVITY;
-
- return ahci_transmit_led_message(ap, state, size);
-}
-
-static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
-{
- struct ata_link *link = dev->link;
- struct ata_port *ap = link->ap;
- struct ahci_port_priv *pp = ap->private_data;
- struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
- u32 port_led_state = emp->led_state;
-
- /* save the desired Activity LED behavior */
- if (val == OFF) {
- /* clear LFLAG */
- link->flags &= ~(ATA_LFLAG_SW_ACTIVITY);
-
- /* set the LED to OFF */
- port_led_state &= EM_MSG_LED_VALUE_OFF;
- port_led_state |= (ap->port_no | (link->pmp << 8));
- ahci_transmit_led_message(ap, port_led_state, 4);
- } else {
- link->flags |= ATA_LFLAG_SW_ACTIVITY;
- if (val == BLINK_OFF) {
- /* set LED to ON for idle */
- port_led_state &= EM_MSG_LED_VALUE_OFF;
- port_led_state |= (ap->port_no | (link->pmp << 8));
- port_led_state |= EM_MSG_LED_VALUE_ON; /* check this */
- ahci_transmit_led_message(ap, port_led_state, 4);
- }
- }
- emp->blink_policy = val;
- return 0;
-}
-
-static ssize_t ahci_activity_show(struct ata_device *dev, char *buf)
-{
- struct ata_link *link = dev->link;
- struct ata_port *ap = link->ap;
- struct ahci_port_priv *pp = ap->private_data;
- struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
-
- /* display the saved value of activity behavior for this
- * disk.
- */
- return sprintf(buf, "%d\n", emp->blink_policy);
-}
-
-static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
- int port_no, void __iomem *mmio,
- void __iomem *port_mmio)
-{
- const char *emsg = NULL;
- int rc;
- u32 tmp;
-
- /* make sure port is not active */
- rc = ahci_deinit_port(ap, &emsg);
- if (rc)
- dev_printk(KERN_WARNING, &pdev->dev,
- "%s (%d)\n", emsg, rc);
-
- /* clear SError */
- tmp = readl(port_mmio + PORT_SCR_ERR);
- VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
- writel(tmp, port_mmio + PORT_SCR_ERR);
-
- /* clear port IRQ */
- tmp = readl(port_mmio + PORT_IRQ_STAT);
- VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
- if (tmp)
- writel(tmp, port_mmio + PORT_IRQ_STAT);
-
- writel(1 << port_no, mmio + HOST_IRQ_STAT);
-}
-
-static void ahci_init_controller(struct ata_host *host)
+static void ahci_pci_init_controller(struct ata_host *host)
{
struct ahci_host_priv *hpriv = host->private_data;
struct pci_dev *pdev = to_pci_dev(host->dev);
- void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
- int i;
void __iomem *port_mmio;
u32 tmp;
int mv;
@@ -1528,222 +424,7 @@ static void ahci_init_controller(struct ata_host *host)
writel(tmp, port_mmio + PORT_IRQ_STAT);
}
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
-
- port_mmio = ahci_port_base(ap);
- if (ata_port_is_dummy(ap))
- continue;
-
- ahci_port_init(pdev, ap, i, mmio, port_mmio);
- }
-
- tmp = readl(mmio + HOST_CTL);
- VPRINTK("HOST_CTL 0x%x\n", tmp);
- writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
- tmp = readl(mmio + HOST_CTL);
- VPRINTK("HOST_CTL 0x%x\n", tmp);
-}
-
-static void ahci_dev_config(struct ata_device *dev)
-{
- struct ahci_host_priv *hpriv = dev->link->ap->host->private_data;
-
- if (hpriv->flags & AHCI_HFLAG_SECT255) {
- dev->max_sectors = 255;
- ata_dev_printk(dev, KERN_INFO,
- "SB600 AHCI: limiting to 255 sectors per cmd\n");
- }
-}
-
-static unsigned int ahci_dev_classify(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ata_taskfile tf;
- u32 tmp;
-
- tmp = readl(port_mmio + PORT_SIG);
- tf.lbah = (tmp >> 24) & 0xff;
- tf.lbam = (tmp >> 16) & 0xff;
- tf.lbal = (tmp >> 8) & 0xff;
- tf.nsect = (tmp) & 0xff;
-
- return ata_dev_classify(&tf);
-}
-
-static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
- u32 opts)
-{
- dma_addr_t cmd_tbl_dma;
-
- cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
-
- pp->cmd_slot[tag].opts = cpu_to_le32(opts);
- pp->cmd_slot[tag].status = 0;
- pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
- pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
-}
-
-static int ahci_kick_engine(struct ata_port *ap, int force_restart)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ahci_host_priv *hpriv = ap->host->private_data;
- u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
- u32 tmp;
- int busy, rc;
-
- /* do we need to kick the port? */
- busy = status & (ATA_BUSY | ATA_DRQ);
- if (!busy && !force_restart)
- return 0;
-
- /* stop engine */
- rc = ahci_stop_engine(ap);
- if (rc)
- goto out_restart;
-
- /* need to do CLO? */
- if (!busy) {
- rc = 0;
- goto out_restart;
- }
-
- if (!(hpriv->cap & HOST_CAP_CLO)) {
- rc = -EOPNOTSUPP;
- goto out_restart;
- }
-
- /* perform CLO */
- tmp = readl(port_mmio + PORT_CMD);
- tmp |= PORT_CMD_CLO;
- writel(tmp, port_mmio + PORT_CMD);
-
- rc = 0;
- tmp = ata_wait_register(port_mmio + PORT_CMD,
- PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
- if (tmp & PORT_CMD_CLO)
- rc = -EIO;
-
- /* restart engine */
- out_restart:
- ahci_start_engine(ap);
- return rc;
-}
-
-static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
- struct ata_taskfile *tf, int is_cmd, u16 flags,
- unsigned long timeout_msec)
-{
- const u32 cmd_fis_len = 5; /* five dwords */
- struct ahci_port_priv *pp = ap->private_data;
- void __iomem *port_mmio = ahci_port_base(ap);
- u8 *fis = pp->cmd_tbl;
- u32 tmp;
-
- /* prep the command */
- ata_tf_to_fis(tf, pmp, is_cmd, fis);
- ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
-
- /* issue & wait */
- writel(1, port_mmio + PORT_CMD_ISSUE);
-
- if (timeout_msec) {
- tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
- 1, timeout_msec);
- if (tmp & 0x1) {
- ahci_kick_engine(ap, 1);
- return -EBUSY;
- }
- } else
- readl(port_mmio + PORT_CMD_ISSUE); /* flush */
-
- return 0;
-}
-
-static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
- int pmp, unsigned long deadline,
- int (*check_ready)(struct ata_link *link))
-{
- struct ata_port *ap = link->ap;
- struct ahci_host_priv *hpriv = ap->host->private_data;
- const char *reason = NULL;
- unsigned long now, msecs;
- struct ata_taskfile tf;
- int rc;
-
- DPRINTK("ENTER\n");
-
- /* prepare for SRST (AHCI-1.1 10.4.1) */
- rc = ahci_kick_engine(ap, 1);
- if (rc && rc != -EOPNOTSUPP)
- ata_link_printk(link, KERN_WARNING,
- "failed to reset engine (errno=%d)\n", rc);
-
- ata_tf_init(link->device, &tf);
-
- /* issue the first D2H Register FIS */
- msecs = 0;
- now = jiffies;
- if (time_after(now, deadline))
- msecs = jiffies_to_msecs(deadline - now);
-
- tf.ctl |= ATA_SRST;
- if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
- AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
- rc = -EIO;
- reason = "1st FIS failed";
- goto fail;
- }
-
- /* spec says at least 5us, but be generous and sleep for 1ms */
- msleep(1);
-
- /* issue the second D2H Register FIS */
- tf.ctl &= ~ATA_SRST;
- ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
-
- /* wait for link to become ready */
- rc = ata_wait_after_reset(link, deadline, check_ready);
- if (rc == -EBUSY && hpriv->flags & AHCI_HFLAG_SRST_TOUT_IS_OFFLINE) {
- /*
- * Workaround for cases where link online status can't
- * be trusted. Treat device readiness timeout as link
- * offline.
- */
- ata_link_printk(link, KERN_INFO,
- "device not ready, treating as offline\n");
- *class = ATA_DEV_NONE;
- } else if (rc) {
- /* link occupied, -ENODEV too is an error */
- reason = "device not ready";
- goto fail;
- } else
- *class = ahci_dev_classify(ap);
-
- DPRINTK("EXIT, class=%u\n", *class);
- return 0;
-
- fail:
- ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
- return rc;
-}
-
-static int ahci_check_ready(struct ata_link *link)
-{
- void __iomem *port_mmio = ahci_port_base(link->ap);
- u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
-
- return ata_check_ready(status);
-}
-
-static int ahci_softreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
-{
- int pmp = sata_srst_pmp(link);
-
- DPRINTK("ENTER\n");
-
- return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
+ ahci_init_controller(host);
}
static int ahci_sb600_check_ready(struct ata_link *link)
@@ -1795,38 +476,6 @@ static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
return rc;
}
-static int ahci_hardreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
-{
- const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
- struct ata_port *ap = link->ap;
- struct ahci_port_priv *pp = ap->private_data;
- u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
- struct ata_taskfile tf;
- bool online;
- int rc;
-
- DPRINTK("ENTER\n");
-
- ahci_stop_engine(ap);
-
- /* clear D2H reception area to properly wait for D2H FIS */
- ata_tf_init(link->device, &tf);
- tf.command = 0x80;
- ata_tf_to_fis(&tf, 0, 0, d2h_fis);
-
- rc = sata_link_hardreset(link, timing, deadline, &online,
- ahci_check_ready);
-
- ahci_start_engine(ap);
-
- if (online)
- *class = ahci_dev_classify(ap);
-
- DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
- return rc;
-}
-
static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
@@ -1890,453 +539,17 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
rc = ata_wait_after_reset(link, jiffies + 2 * HZ,
ahci_check_ready);
if (rc)
- ahci_kick_engine(ap, 0);
+ ahci_kick_engine(ap);
}
return rc;
}
-static void ahci_postreset(struct ata_link *link, unsigned int *class)
-{
- struct ata_port *ap = link->ap;
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 new_tmp, tmp;
-
- ata_std_postreset(link, class);
-
- /* Make sure port's ATAPI bit is set appropriately */
- new_tmp = tmp = readl(port_mmio + PORT_CMD);
- if (*class == ATA_DEV_ATAPI)
- new_tmp |= PORT_CMD_ATAPI;
- else
- new_tmp &= ~PORT_CMD_ATAPI;
- if (new_tmp != tmp) {
- writel(new_tmp, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
- }
-}
-
-static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
-{
- struct scatterlist *sg;
- struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
- unsigned int si;
-
- VPRINTK("ENTER\n");
-
- /*
- * Next, the S/G list.
- */
- for_each_sg(qc->sg, sg, qc->n_elem, si) {
- dma_addr_t addr = sg_dma_address(sg);
- u32 sg_len = sg_dma_len(sg);
-
- ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
- ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
- ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
- }
-
- return si;
-}
-
-static void ahci_qc_prep(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct ahci_port_priv *pp = ap->private_data;
- int is_atapi = ata_is_atapi(qc->tf.protocol);
- void *cmd_tbl;
- u32 opts;
- const u32 cmd_fis_len = 5; /* five dwords */
- unsigned int n_elem;
-
- /*
- * Fill in command table information. First, the header,
- * a SATA Register - Host to Device command FIS.
- */
- cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
-
- ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
- if (is_atapi) {
- memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
- memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
- }
-
- n_elem = 0;
- if (qc->flags & ATA_QCFLAG_DMAMAP)
- n_elem = ahci_fill_sg(qc, cmd_tbl);
-
- /*
- * Fill in command slot information.
- */
- opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
- if (qc->tf.flags & ATA_TFLAG_WRITE)
- opts |= AHCI_CMD_WRITE;
- if (is_atapi)
- opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
-
- ahci_fill_cmd_slot(pp, qc->tag, opts);
-}
-
-static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
-{
- struct ahci_host_priv *hpriv = ap->host->private_data;
- struct ahci_port_priv *pp = ap->private_data;
- struct ata_eh_info *host_ehi = &ap->link.eh_info;
- struct ata_link *link = NULL;
- struct ata_queued_cmd *active_qc;
- struct ata_eh_info *active_ehi;
- u32 serror;
-
- /* determine active link */
- ata_for_each_link(link, ap, EDGE)
- if (ata_link_active(link))
- break;
- if (!link)
- link = &ap->link;
-
- active_qc = ata_qc_from_tag(ap, link->active_tag);
- active_ehi = &link->eh_info;
-
- /* record irq stat */
- ata_ehi_clear_desc(host_ehi);
- ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
-
- /* AHCI needs SError cleared; otherwise, it might lock up */
- ahci_scr_read(&ap->link, SCR_ERROR, &serror);
- ahci_scr_write(&ap->link, SCR_ERROR, serror);
- host_ehi->serror |= serror;
-
- /* some controllers set IRQ_IF_ERR on device errors, ignore it */
- if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
- irq_stat &= ~PORT_IRQ_IF_ERR;
-
- if (irq_stat & PORT_IRQ_TF_ERR) {
- /* If qc is active, charge it; otherwise, the active
- * link. There's no active qc on NCQ errors. It will
- * be determined by EH by reading log page 10h.
- */
- if (active_qc)
- active_qc->err_mask |= AC_ERR_DEV;
- else
- active_ehi->err_mask |= AC_ERR_DEV;
-
- if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
- host_ehi->serror &= ~SERR_INTERNAL;
- }
-
- if (irq_stat & PORT_IRQ_UNK_FIS) {
- u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
-
- active_ehi->err_mask |= AC_ERR_HSM;
- active_ehi->action |= ATA_EH_RESET;
- ata_ehi_push_desc(active_ehi,
- "unknown FIS %08x %08x %08x %08x" ,
- unk[0], unk[1], unk[2], unk[3]);
- }
-
- if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) {
- active_ehi->err_mask |= AC_ERR_HSM;
- active_ehi->action |= ATA_EH_RESET;
- ata_ehi_push_desc(active_ehi, "incorrect PMP");
- }
-
- if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
- host_ehi->err_mask |= AC_ERR_HOST_BUS;
- host_ehi->action |= ATA_EH_RESET;
- ata_ehi_push_desc(host_ehi, "host bus error");
- }
-
- if (irq_stat & PORT_IRQ_IF_ERR) {
- host_ehi->err_mask |= AC_ERR_ATA_BUS;
- host_ehi->action |= ATA_EH_RESET;
- ata_ehi_push_desc(host_ehi, "interface fatal error");
- }
-
- if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
- ata_ehi_hotplugged(host_ehi);
- ata_ehi_push_desc(host_ehi, "%s",
- irq_stat & PORT_IRQ_CONNECT ?
- "connection status changed" : "PHY RDY changed");
- }
-
- /* okay, let's hand over to EH */
-
- if (irq_stat & PORT_IRQ_FREEZE)
- ata_port_freeze(ap);
- else
- ata_port_abort(ap);
-}
-
-static void ahci_port_intr(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ata_eh_info *ehi = &ap->link.eh_info;
- struct ahci_port_priv *pp = ap->private_data;
- struct ahci_host_priv *hpriv = ap->host->private_data;
- int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
- u32 status, qc_active;
- int rc;
-
- status = readl(port_mmio + PORT_IRQ_STAT);
- writel(status, port_mmio + PORT_IRQ_STAT);
-
- /* ignore BAD_PMP while resetting */
- if (unlikely(resetting))
- status &= ~PORT_IRQ_BAD_PMP;
-
- /* If we are getting PhyRdy, this is
- * just a power state change, we should
- * clear out this, plus the PhyRdy/Comm
- * Wake bits from Serror
- */
- if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
- (status & PORT_IRQ_PHYRDY)) {
- status &= ~PORT_IRQ_PHYRDY;
- ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
- }
-
- if (unlikely(status & PORT_IRQ_ERROR)) {
- ahci_error_intr(ap, status);
- return;
- }
-
- if (status & PORT_IRQ_SDB_FIS) {
- /* If SNotification is available, leave notification
- * handling to sata_async_notification(). If not,
- * emulate it by snooping SDB FIS RX area.
- *
- * Snooping FIS RX area is probably cheaper than
- * poking SNotification but some constrollers which
- * implement SNotification, ICH9 for example, don't
- * store AN SDB FIS into receive area.
- */
- if (hpriv->cap & HOST_CAP_SNTF)
- sata_async_notification(ap);
- else {
- /* If the 'N' bit in word 0 of the FIS is set,
- * we just received asynchronous notification.
- * Tell libata about it.
- */
- const __le32 *f = pp->rx_fis + RX_FIS_SDB;
- u32 f0 = le32_to_cpu(f[0]);
-
- if (f0 & (1 << 15))
- sata_async_notification(ap);
- }
- }
-
- /* pp->active_link is valid iff any command is in flight */
- if (ap->qc_active && pp->active_link->sactive)
- qc_active = readl(port_mmio + PORT_SCR_ACT);
- else
- qc_active = readl(port_mmio + PORT_CMD_ISSUE);
-
- rc = ata_qc_complete_multiple(ap, qc_active);
-
- /* while resetting, invalid completions are expected */
- if (unlikely(rc < 0 && !resetting)) {
- ehi->err_mask |= AC_ERR_HSM;
- ehi->action |= ATA_EH_RESET;
- ata_port_freeze(ap);
- }
-}
-
-static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
-{
- struct ata_host *host = dev_instance;
- struct ahci_host_priv *hpriv;
- unsigned int i, handled = 0;
- void __iomem *mmio;
- u32 irq_stat, irq_masked;
-
- VPRINTK("ENTER\n");
-
- hpriv = host->private_data;
- mmio = host->iomap[AHCI_PCI_BAR];
-
- /* sigh. 0xffffffff is a valid return from h/w */
- irq_stat = readl(mmio + HOST_IRQ_STAT);
- if (!irq_stat)
- return IRQ_NONE;
-
- irq_masked = irq_stat & hpriv->port_map;
-
- spin_lock(&host->lock);
-
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap;
-
- if (!(irq_masked & (1 << i)))
- continue;
-
- ap = host->ports[i];
- if (ap) {
- ahci_port_intr(ap);
- VPRINTK("port %u\n", i);
- } else {
- VPRINTK("port %u (no irq)\n", i);
- if (ata_ratelimit())
- dev_printk(KERN_WARNING, host->dev,
- "interrupt on disabled port %u\n", i);
- }
-
- handled = 1;
- }
-
- /* HOST_IRQ_STAT behaves as level triggered latch meaning that
- * it should be cleared after all the port events are cleared;
- * otherwise, it will raise a spurious interrupt after each
- * valid one. Please read section 10.6.2 of ahci 1.1 for more
- * information.
- *
- * Also, use the unmasked value to clear interrupt as spurious
- * pending event on a dummy port might cause screaming IRQ.
- */
- writel(irq_stat, mmio + HOST_IRQ_STAT);
-
- spin_unlock(&host->lock);
-
- VPRINTK("EXIT\n");
-
- return IRQ_RETVAL(handled);
-}
-
-static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ahci_port_priv *pp = ap->private_data;
-
- /* Keep track of the currently active link. It will be used
- * in completion path to determine whether NCQ phase is in
- * progress.
- */
- pp->active_link = qc->dev->link;
-
- if (qc->tf.protocol == ATA_PROT_NCQ)
- writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
- writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
-
- ahci_sw_activity(qc->dev->link);
-
- return 0;
-}
-
-static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
-{
- struct ahci_port_priv *pp = qc->ap->private_data;
- u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
-
- ata_tf_from_fis(d2h_fis, &qc->result_tf);
- return true;
-}
-
-static void ahci_freeze(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
-
- /* turn IRQ off */
- writel(0, port_mmio + PORT_IRQ_MASK);
-}
-
-static void ahci_thaw(struct ata_port *ap)
-{
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(ap);
- u32 tmp;
- struct ahci_port_priv *pp = ap->private_data;
-
- /* clear IRQ */
- tmp = readl(port_mmio + PORT_IRQ_STAT);
- writel(tmp, port_mmio + PORT_IRQ_STAT);
- writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
-
- /* turn IRQ back on */
- writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
-}
-
-static void ahci_error_handler(struct ata_port *ap)
-{
- if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
- /* restart engine */
- ahci_stop_engine(ap);
- ahci_start_engine(ap);
- }
-
- sata_pmp_error_handler(ap);
-}
-
-static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
-
- /* make DMA engine forget about the failed command */
- if (qc->flags & ATA_QCFLAG_FAILED)
- ahci_kick_engine(ap, 1);
-}
-
-static void ahci_pmp_attach(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ahci_port_priv *pp = ap->private_data;
- u32 cmd;
-
- cmd = readl(port_mmio + PORT_CMD);
- cmd |= PORT_CMD_PMP;
- writel(cmd, port_mmio + PORT_CMD);
-
- pp->intr_mask |= PORT_IRQ_BAD_PMP;
- writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
-}
-
-static void ahci_pmp_detach(struct ata_port *ap)
-{
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ahci_port_priv *pp = ap->private_data;
- u32 cmd;
-
- cmd = readl(port_mmio + PORT_CMD);
- cmd &= ~PORT_CMD_PMP;
- writel(cmd, port_mmio + PORT_CMD);
-
- pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
- writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
-}
-
-static int ahci_port_resume(struct ata_port *ap)
-{
- ahci_power_up(ap);
- ahci_start_port(ap);
-
- if (sata_pmp_attached(ap))
- ahci_pmp_attach(ap);
- else
- ahci_pmp_detach(ap);
-
- return 0;
-}
-
#ifdef CONFIG_PM
-static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
-{
- const char *emsg = NULL;
- int rc;
-
- rc = ahci_deinit_port(ap, &emsg);
- if (rc == 0)
- ahci_power_down(ap);
- else {
- ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
- ahci_start_port(ap);
- }
-
- return rc;
-}
-
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
struct ahci_host_priv *hpriv = host->private_data;
- void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
+ void __iomem *mmio = hpriv->mmio;
u32 ctl;
if (mesg.event & PM_EVENT_SUSPEND &&
@@ -2370,11 +583,11 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
return rc;
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
- rc = ahci_reset_controller(host);
+ rc = ahci_pci_reset_controller(host);
if (rc)
return rc;
- ahci_init_controller(host);
+ ahci_pci_init_controller(host);
}
ata_host_resume(host);
@@ -2383,72 +596,6 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
}
#endif
-static int ahci_port_start(struct ata_port *ap)
-{
- struct device *dev = ap->host->dev;
- struct ahci_port_priv *pp;
- void *mem;
- dma_addr_t mem_dma;
-
- pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
- if (!pp)
- return -ENOMEM;
-
- mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
- GFP_KERNEL);
- if (!mem)
- return -ENOMEM;
- memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
-
- /*
- * First item in chunk of DMA memory: 32-slot command table,
- * 32 bytes each in size
- */
- pp->cmd_slot = mem;
- pp->cmd_slot_dma = mem_dma;
-
- mem += AHCI_CMD_SLOT_SZ;
- mem_dma += AHCI_CMD_SLOT_SZ;
-
- /*
- * Second item: Received-FIS area
- */
- pp->rx_fis = mem;
- pp->rx_fis_dma = mem_dma;
-
- mem += AHCI_RX_FIS_SZ;
- mem_dma += AHCI_RX_FIS_SZ;
-
- /*
- * Third item: data area for storing a single command
- * and its scatter-gather table
- */
- pp->cmd_tbl = mem;
- pp->cmd_tbl_dma = mem_dma;
-
- /*
- * Save off initial list of interrupts to be enabled.
- * This could be changed later
- */
- pp->intr_mask = DEF_PORT_IRQ;
-
- ap->private_data = pp;
-
- /* engage engines, captain */
- return ahci_port_resume(ap);
-}
-
-static void ahci_port_stop(struct ata_port *ap)
-{
- const char *emsg = NULL;
- int rc;
-
- /* de-initialize port */
- rc = ahci_deinit_port(ap, &emsg);
- if (rc)
- ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
-}
-
static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
{
int rc;
@@ -2481,30 +628,12 @@ static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
return 0;
}
-static void ahci_print_info(struct ata_host *host)
+static void ahci_pci_print_info(struct ata_host *host)
{
- struct ahci_host_priv *hpriv = host->private_data;
struct pci_dev *pdev = to_pci_dev(host->dev);
- void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
- u32 vers, cap, impl, speed;
- const char *speed_s;
u16 cc;
const char *scc_s;
- vers = readl(mmio + HOST_VERSION);
- cap = hpriv->cap;
- impl = hpriv->port_map;
-
- speed = (cap >> 20) & 0xf;
- if (speed == 1)
- speed_s = "1.5";
- else if (speed == 2)
- speed_s = "3";
- else if (speed == 3)
- speed_s = "6";
- else
- speed_s = "?";
-
pci_read_config_word(pdev, 0x0a, &cc);
if (cc == PCI_CLASS_STORAGE_IDE)
scc_s = "IDE";
@@ -2515,46 +644,7 @@ static void ahci_print_info(struct ata_host *host)
else
scc_s = "unknown";
- dev_printk(KERN_INFO, &pdev->dev,
- "AHCI %02x%02x.%02x%02x "
- "%u slots %u ports %s Gbps 0x%x impl %s mode\n"
- ,
-
- (vers >> 24) & 0xff,
- (vers >> 16) & 0xff,
- (vers >> 8) & 0xff,
- vers & 0xff,
-
- ((cap >> 8) & 0x1f) + 1,
- (cap & 0x1f) + 1,
- speed_s,
- impl,
- scc_s);
-
- dev_printk(KERN_INFO, &pdev->dev,
- "flags: "
- "%s%s%s%s%s%s%s"
- "%s%s%s%s%s%s%s"
- "%s\n"
- ,
-
- cap & (1 << 31) ? "64bit " : "",
- cap & (1 << 30) ? "ncq " : "",
- cap & (1 << 29) ? "sntf " : "",
- cap & (1 << 28) ? "ilck " : "",
- cap & (1 << 27) ? "stag " : "",
- cap & (1 << 26) ? "pm " : "",
- cap & (1 << 25) ? "led " : "",
-
- cap & (1 << 24) ? "clo " : "",
- cap & (1 << 19) ? "nz " : "",
- cap & (1 << 18) ? "only " : "",
- cap & (1 << 17) ? "pmp " : "",
- cap & (1 << 15) ? "pio " : "",
- cap & (1 << 14) ? "slum " : "",
- cap & (1 << 13) ? "part " : "",
- cap & (1 << 6) ? "ems ": ""
- );
+ ahci_print_info(host, scc_s);
}
/* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
@@ -2789,6 +879,55 @@ static bool ahci_broken_online(struct pci_dev *pdev)
return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
}
+#ifdef CONFIG_ATA_ACPI
+static void ahci_gtf_filter_workaround(struct ata_host *host)
+{
+ static const struct dmi_system_id sysids[] = {
+ /*
+ * Aspire 3810T issues a bunch of SATA enable commands
+ * via _GTF including an invalid one and one which is
+ * rejected by the device. Among the successful ones
+ * is FPDMA non-zero offset enable which when enabled
+ * only on the drive side leads to NCQ command
+ * failures. Filter it out.
+ */
+ {
+ .ident = "Aspire 3810T",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3810T"),
+ },
+ .driver_data = (void *)ATA_ACPI_FILTER_FPDMA_OFFSET,
+ },
+ { }
+ };
+ const struct dmi_system_id *dmi = dmi_first_match(sysids);
+ unsigned int filter;
+ int i;
+
+ if (!dmi)
+ return;
+
+ filter = (unsigned long)dmi->driver_data;
+ dev_printk(KERN_INFO, host->dev,
+ "applying extra ACPI _GTF filter 0x%x for %s\n",
+ filter, dmi->ident);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ struct ata_link *link;
+ struct ata_device *dev;
+
+ ata_for_each_link(link, ap, EDGE)
+ ata_for_each_dev(dev, link, ALL)
+ dev->gtf_filter |= filter;
+ }
+}
+#else
+static inline void ahci_gtf_filter_workaround(struct ata_host *host)
+{}
+#endif
+
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
@@ -2864,33 +1003,19 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
pci_enable_msi(pdev);
+ hpriv->mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
+
/* save initial config */
- ahci_save_initial_config(pdev, hpriv);
+ ahci_pci_save_initial_config(pdev, hpriv);
/* prepare host */
if (hpriv->cap & HOST_CAP_NCQ)
- pi.flags |= ATA_FLAG_NCQ;
+ pi.flags |= ATA_FLAG_NCQ | ATA_FLAG_FPDMA_AA;
if (hpriv->cap & HOST_CAP_PMP)
pi.flags |= ATA_FLAG_PMP;
- if (ahci_em_messages && (hpriv->cap & HOST_CAP_EMS)) {
- u8 messages;
- void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
- u32 em_loc = readl(mmio + HOST_EM_LOC);
- u32 em_ctl = readl(mmio + HOST_EM_CTL);
-
- messages = (em_ctl & EM_CTRL_MSG_TYPE) >> 16;
-
- /* we only support LED message type right now */
- if ((messages & 0x01) && (ahci_em_messages == 1)) {
- /* store em_loc */
- hpriv->em_loc = ((em_loc >> 16) * 4);
- pi.flags |= ATA_FLAG_EM;
- if (!(em_ctl & EM_CTL_ALHD))
- pi.flags |= ATA_FLAG_SW_ACTIVITY;
- }
- }
+ ahci_set_em_messages(hpriv, &pi);
if (ahci_broken_system_poweroff(pdev)) {
pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN;
@@ -2920,7 +1045,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
if (!host)
return -ENOMEM;
- host->iomap = pcim_iomap_table(pdev);
host->private_data = hpriv;
if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
@@ -2954,17 +1078,20 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* apply workaround for ASUS P5W DH Deluxe mainboard */
ahci_p5wdh_workaround(host);
+ /* apply gtf filter quirk */
+ ahci_gtf_filter_workaround(host);
+
/* initialize adapter */
rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
if (rc)
return rc;
- rc = ahci_reset_controller(host);
+ rc = ahci_pci_reset_controller(host);
if (rc)
return rc;
- ahci_init_controller(host);
- ahci_print_info(host);
+ ahci_pci_init_controller(host);
+ ahci_pci_print_info(host);
pci_set_master(pdev);
return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 072ba5ea138f..98af50f16e0c 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2299,29 +2299,49 @@ static inline u8 ata_dev_knobble(struct ata_device *dev)
return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
}
-static void ata_dev_config_ncq(struct ata_device *dev,
+static int ata_dev_config_ncq(struct ata_device *dev,
char *desc, size_t desc_sz)
{
struct ata_port *ap = dev->link->ap;
int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
+ unsigned int err_mask;
+ char *aa_desc = "";
if (!ata_id_has_ncq(dev->id)) {
desc[0] = '\0';
- return;
+ return 0;
}
if (dev->horkage & ATA_HORKAGE_NONCQ) {
snprintf(desc, desc_sz, "NCQ (not used)");
- return;
+ return 0;
}
if (ap->flags & ATA_FLAG_NCQ) {
hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE - 1);
dev->flags |= ATA_DFLAG_NCQ;
}
+ if (!(dev->horkage & ATA_HORKAGE_BROKEN_FPDMA_AA) &&
+ (ap->flags & ATA_FLAG_FPDMA_AA) &&
+ ata_id_has_fpdma_aa(dev->id)) {
+ err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_ENABLE,
+ SATA_FPDMA_AA);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to enable AA"
+ "(error_mask=0x%x)\n", err_mask);
+ if (err_mask != AC_ERR_DEV) {
+ dev->horkage |= ATA_HORKAGE_BROKEN_FPDMA_AA;
+ return -EIO;
+ }
+ } else
+ aa_desc = ", AA";
+ }
+
if (hdepth >= ddepth)
- snprintf(desc, desc_sz, "NCQ (depth %d)", ddepth);
+ snprintf(desc, desc_sz, "NCQ (depth %d)%s", ddepth, aa_desc);
else
- snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
+ snprintf(desc, desc_sz, "NCQ (depth %d/%d)%s", hdepth,
+ ddepth, aa_desc);
+ return 0;
}
/**
@@ -2461,7 +2481,7 @@ int ata_dev_configure(struct ata_device *dev)
if (ata_id_has_lba(id)) {
const char *lba_desc;
- char ncq_desc[20];
+ char ncq_desc[24];
lba_desc = "LBA";
dev->flags |= ATA_DFLAG_LBA;
@@ -2475,7 +2495,9 @@ int ata_dev_configure(struct ata_device *dev)
}
/* config NCQ */
- ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
+ rc = ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
+ if (rc)
+ return rc;
/* print device info to dmesg */
if (ata_msg_drv(ap) && print_info) {
diff --git a/drivers/ata/pata_fsl.c b/drivers/ata/pata_fsl.c
index c1d05282da03..955095039257 100644
--- a/drivers/ata/pata_fsl.c
+++ b/drivers/ata/pata_fsl.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -766,10 +766,11 @@ static int __devinit pata_fsl_probe(struct platform_device *pdev)
/*
* Set up resources
*/
- if (unlikely(pdev->num_resources != 3)) {
+ if (unlikely(pdev->num_resources != 2)) {
dev_err(&pdev->dev, "invalid number of resources\n");
return -EINVAL;
}
+
/*
* Get an ata_host structure for this device
*/
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index dc99e26f8e5b..c4647f5b6a22 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -136,7 +136,7 @@ static unsigned int ata_data_xfer_8bit(struct ata_device *dev,
*
*/
-void pcmcia_8bit_drain_fifo(struct ata_queued_cmd *qc)
+static void pcmcia_8bit_drain_fifo(struct ata_queued_cmd *qc)
{
int count;
struct ata_port *ap;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 8efaa5ca8a03..49f086977c37 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -444,7 +444,7 @@ config MXC_IIM
config MXS_VIIM
tristate "MXS Virtual IIM device driver"
- depends on (ARCH_STMP3XXX || ARCH_MXS)
+ depends on (ARCH_STMP3XXX || ARCH_MXS || ARCH_MX5)
help
Support for access to MXS Virtual IIM device, most people should say N here.
@@ -564,6 +564,22 @@ config BFIN_OTP_WRITE_ENABLE
If unsure, say N.
+config FSL_OTP
+ tristate "Freescale On-Chip OTP Memory Support"
+ depends on (ARCH_MX23 || ARCH_MX28 || ARCH_MX50)
+ default n
+ help
+ If you say Y here, you will get support for a character device
+ interface into the One Time Programmable memory pages that are
+ stored on the iMX23/28/50 processor. This will not get you access
+ to the secure memory pages however. You will need to write your
+ own secure code and reader for that.
+
+ To compile this driver as a module, choose M here: the module
+ will be called fsl_otp.
+
+ If unsure, it is safe to say Y.
+
config PRINTER
tristate "Parallel printer support"
depends on PARPORT
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index c711f02de8f7..898ce27e335d 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_IBM_BSR) += bsr.o
obj-$(CONFIG_SGI_MBCS) += mbcs.o
obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
obj-$(CONFIG_BFIN_OTP) += bfin-otp.o
+obj-$(CONFIG_FSL_OTP) += fsl_otp.o
obj-$(CONFIG_PRINTER) += lp.o
diff --git a/drivers/char/hw_random/fsl-rngc.c b/drivers/char/hw_random/fsl-rngc.c
index 9bf78e846fa0..9e788f97c4d8 100644
--- a/drivers/char/hw_random/fsl-rngc.c
+++ b/drivers/char/hw_random/fsl-rngc.c
@@ -1,7 +1,7 @@
/*
* RNG driver for Freescale RNGC
*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2010 Freescale Semiconductor, Inc.
*/
/*
@@ -42,7 +42,6 @@
#include <linux/interrupt.h>
#include <linux/hw_random.h>
#include <linux/io.h>
-#include <asm/hardware.h>
#define RNGC_VERSION_MAJOR3 3
@@ -292,7 +291,7 @@ static int __init fsl_rngc_probe(struct platform_device *pdev)
if (rng_dev)
return -EBUSY;
- clk = clk_get(NULL, "rng_clk");
+ clk = clk_get(&pdev->dev, "rng_clk");
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "Can not get rng_clk\n");
@@ -334,9 +333,17 @@ static int __init fsl_rngc_probe(struct platform_device *pdev)
static int __exit fsl_rngc_remove(struct platform_device *pdev)
{
+ struct clk *clk;
struct resource *mem = dev_get_drvdata(&pdev->dev);
void __iomem *rngc_base = (void __iomem *)fsl_rngc.priv;
+ clk = clk_get(&pdev->dev, "rng_clk");
+
+ if (IS_ERR(clk))
+ dev_err(&pdev->dev, "Can not get rng_clk\n");
+ else
+ clk_disable(clk);
+
hwrng_unregister(&fsl_rngc);
release_resource(mem);
@@ -346,12 +353,47 @@ static int __exit fsl_rngc_remove(struct platform_device *pdev)
return 0;
}
+static int fsl_rngc_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+#ifdef CONFIG_PM
+ struct clk *clk = clk_get(&pdev->dev, "rng_clk");
+
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "Can not get rng_clk\n");
+ return PTR_ERR(clk);
+ }
+
+ clk_disable(clk);
+#endif
+
+ return 0;
+}
+
+static int fsl_rngc_resume(struct platform_device *pdev)
+{
+#ifdef CONFIG_PM
+ struct clk *clk = clk_get(&pdev->dev, "rng_clk");
+
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "Can not get rng_clk\n");
+ return PTR_ERR(clk);
+ }
+
+ clk_enable(clk);
+#endif
+
+ return 0;
+}
+
static struct platform_driver fsl_rngc_driver = {
.driver = {
.name = "fsl_rngc",
.owner = THIS_MODULE,
},
.remove = __exit_p(fsl_rngc_remove),
+ .suspend = fsl_rngc_suspend,
+ .resume = fsl_rngc_resume,
};
static int __init mod_init(void)
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 9c2919a431a8..5057cb958230 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -211,7 +211,7 @@ config CRYPTO_DEV_PPC4XX
config CRYPTO_DEV_DCP
tristate "Support for the DCP engine"
- depends on ARCH_MX28 || ARCH_MX23
+ depends on ARCH_MX28 || ARCH_MX23 || ARCH_MX50
select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
help
diff --git a/drivers/crypto/dcp.c b/drivers/crypto/dcp.c
index a72d73382778..eb7a83d276b7 100644
--- a/drivers/crypto/dcp.c
+++ b/drivers/crypto/dcp.c
@@ -17,10 +17,16 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sysdev.h>
+#include <linux/bitops.h>
#include <linux/crypto.h>
#include <linux/spinlock.h>
+#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/fs.h>
#include <crypto/algapi.h>
#include <crypto/aes.h>
#include <crypto/sha.h>
@@ -29,13 +35,21 @@
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
-
+#include <linux/uaccess.h>
+#include <linux/clk.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <asm/cacheflush.h>
#include <mach/hardware.h>
#include "dcp.h"
+#include "dcp_bootstream_ioctl.h"
+
+/* Following data only used by DCP bootstream interface */
+struct dcpboot_dma_area {
+ struct dcp_hw_packet hw_packet;
+ uint16_t block[16];
+};
struct dcp {
struct device *dev;
@@ -46,6 +60,8 @@ struct dcp {
int dcp_vmi_irq;
int dcp_irq;
u32 dcp_regs_base;
+ ulong clock_state;
+ bool chan_in_use[DCP_NUM_CHANNELS];
/* Following buffers used in hashing to meet 64-byte len alignment */
char *buf1;
@@ -55,6 +71,10 @@ struct dcp {
struct dcp_hash_coherent_block *buf1_desc;
struct dcp_hash_coherent_block *buf2_desc;
struct dcp_hash_coherent_block *user_buf_desc;
+
+ /* Following data only used by DCP bootstream interface */
+ struct dcpboot_dma_area *dcpboot_dma_area;
+ dma_addr_t dcpboot_dma_area_phys;
};
/* cipher flags */
@@ -77,6 +97,10 @@ struct dcp {
#define DCP_FILL 0x5000
#define DCP_MODE_MASK 0xf000
+/* clock defines */
+#define CLOCK_ON 1
+#define CLOCK_OFF 0
+
struct dcp_op {
unsigned int flags;
@@ -159,6 +183,45 @@ struct dcp_hash_op {
/* only one */
static struct dcp *global_sdcp;
+static void dcp_clock(struct dcp *sdcp, ulong state, bool force)
+{
+ u32 chan;
+ struct clk *clk = clk_get(sdcp->dev, "dcp_clk");
+
+ /* unless force is true (used during suspend/resume), if any
+ * channel is running, then clk is already on, and must stay on */
+ if (!force)
+ for (chan = 0; chan < DCP_NUM_CHANNELS; chan++)
+ if (sdcp->chan_in_use[chan])
+ goto exit;
+
+ if (state == CLOCK_OFF) {
+ /* gate at clock source */
+ if (!IS_ERR(clk))
+ clk_disable(clk);
+ /* gate at DCP */
+ else
+ __raw_writel(BM_DCP_CTRL_CLKGATE,
+ sdcp->dcp_regs_base + HW_DCP_CTRL_SET);
+
+ sdcp->clock_state = CLOCK_OFF;
+
+ } else {
+ /* ungate at clock source */
+ if (!IS_ERR(clk))
+ clk_enable(clk);
+ /* ungate at DCP */
+ else
+ __raw_writel(BM_DCP_CTRL_CLKGATE,
+ sdcp->dcp_regs_base + HW_DCP_CTRL_CLR);
+
+ sdcp->clock_state = CLOCK_ON;
+ }
+
+exit:
+ return;
+}
+
static void dcp_perform_op(struct dcp_op *op)
{
struct dcp *sdcp = global_sdcp;
@@ -244,6 +307,8 @@ static void dcp_perform_op(struct dcp_op *op)
/* submit the work */
mutex_lock(mutex);
+ dcp_clock(sdcp, CLOCK_ON, false);
+ sdcp->chan_in_use[chan] = true;
__raw_writel(-1, sdcp->dcp_regs_base + HW_DCP_CHnSTAT_CLR(chan));
@@ -272,8 +337,9 @@ static void dcp_perform_op(struct dcp_op *op)
__raw_readl(sdcp->dcp_regs_base +
HW_DCP_CHnSTAT(chan)) & 0xff);
out:
+ sdcp->chan_in_use[chan] = false;
+ dcp_clock(sdcp, CLOCK_OFF, false);
mutex_unlock(mutex);
-
dma_unmap_single(sdcp->dev, pkt_phys, sizeof(*pkt), DMA_TO_DEVICE);
}
@@ -1043,6 +1109,8 @@ static int dcp_sha_init(struct shash_desc *desc)
struct mutex *mutex = &sdcp->op_mutex[HASH_CHAN];
mutex_lock(mutex);
+ dcp_clock(sdcp, CLOCK_ON, false);
+ sdcp->chan_in_use[HASH_CHAN] = true;
op->length = 0;
@@ -1172,6 +1240,8 @@ static int dcp_sha_final(struct shash_desc *desc, u8 *out)
for (i = 0; i < digest_len; i++)
*out++ = *--digest;
+ sdcp->chan_in_use[HASH_CHAN] = false;
+ dcp_clock(sdcp, CLOCK_OFF, false);
mutex_unlock(mutex);
return ret;
@@ -1245,6 +1315,110 @@ static irqreturn_t dcp_irq(int irq, void *context)
return dcp_common_irq(irq, context);
}
+/* DCP bootstream verification interface: uses OTP key for crypto */
+static int dcp_bootstream_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct dcp *sdcp = global_sdcp;
+ struct dcpboot_dma_area *da = sdcp->dcpboot_dma_area;
+ void __user *argp = (void __user *)arg;
+ int chan = ROM_DCP_CHAN;
+ unsigned long timeout;
+ struct mutex *mutex;
+ int retVal;
+
+ /* be paranoid */
+ if (sdcp == NULL)
+ return -EBADF;
+
+ if (cmd != DBS_ENC && cmd != DBS_DEC)
+ return -EINVAL;
+
+ /* copy to (aligned) block */
+ if (copy_from_user(da->block, argp, 16))
+ return -EFAULT;
+
+ mutex = &sdcp->op_mutex[chan];
+ mutex_lock(mutex);
+ dcp_clock(sdcp, CLOCK_ON, false);
+ sdcp->chan_in_use[chan] = true;
+
+ __raw_writel(-1, sdcp->dcp_regs_base +
+ HW_DCP_CHnSTAT_CLR(ROM_DCP_CHAN));
+ __raw_writel(BF(ROM_DCP_CHAN_MASK, DCP_STAT_IRQ),
+ sdcp->dcp_regs_base + HW_DCP_STAT_CLR);
+
+ da->hw_packet.pNext = 0;
+ da->hw_packet.pkt1 = BM_DCP_PACKET1_DECR_SEMAPHORE |
+ BM_DCP_PACKET1_ENABLE_CIPHER | BM_DCP_PACKET1_OTP_KEY |
+ BM_DCP_PACKET1_INTERRUPT |
+ (cmd == DBS_ENC ? BM_DCP_PACKET1_CIPHER_ENCRYPT : 0);
+ da->hw_packet.pkt2 = BF(0, DCP_PACKET2_CIPHER_CFG) |
+ BF(0, DCP_PACKET2_KEY_SELECT) |
+ BF(BV_DCP_PACKET2_CIPHER_MODE__ECB, DCP_PACKET2_CIPHER_MODE) |
+ BF(BV_DCP_PACKET2_CIPHER_SELECT__AES128, DCP_PACKET2_CIPHER_SELECT);
+ da->hw_packet.pSrc = sdcp->dcpboot_dma_area_phys +
+ offsetof(struct dcpboot_dma_area, block);
+ da->hw_packet.pDst = da->hw_packet.pSrc; /* in-place */
+ da->hw_packet.size = 16;
+ da->hw_packet.pPayload = 0;
+ da->hw_packet.stat = 0;
+
+ /* Load the work packet pointer and bump the channel semaphore */
+ __raw_writel(sdcp->dcpboot_dma_area_phys +
+ offsetof(struct dcpboot_dma_area, hw_packet),
+ sdcp->dcp_regs_base + HW_DCP_CHnCMDPTR(ROM_DCP_CHAN));
+
+ sdcp->wait[chan] = 0;
+ __raw_writel(BF(1, DCP_CHnSEMA_INCREMENT),
+ sdcp->dcp_regs_base + HW_DCP_CHnSEMA(ROM_DCP_CHAN));
+
+ timeout = jiffies + msecs_to_jiffies(100);
+
+ while (time_before(jiffies, timeout) && sdcp->wait[chan] == 0)
+ cpu_relax();
+
+ if (!time_before(jiffies, timeout)) {
+ dev_err(sdcp->dev,
+ "Timeout while waiting for operation to complete\n");
+ retVal = -ETIMEDOUT;
+ goto exit;
+ }
+
+ if ((__raw_readl(sdcp->dcp_regs_base + HW_DCP_CHnSTAT(ROM_DCP_CHAN))
+ & 0xff) != 0) {
+ dev_err(sdcp->dev, "Channel stat error 0x%02x\n",
+ __raw_readl(sdcp->dcp_regs_base +
+ HW_DCP_CHnSTAT(ROM_DCP_CHAN)) & 0xff);
+ retVal = -EFAULT;
+ goto exit;
+ }
+
+ if (copy_to_user(argp, da->block, 16)) {
+ retVal = -EFAULT;
+ goto exit;
+ }
+
+ retVal = 0;
+
+exit:
+ sdcp->chan_in_use[chan] = false;
+ dcp_clock(sdcp, CLOCK_OFF, false);
+ mutex_unlock(mutex);
+ return retVal;
+}
+
+static const struct file_operations dcp_bootstream_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = dcp_bootstream_ioctl,
+};
+
+static struct miscdevice dcp_bootstream_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "dcpboot",
+ .fops = &dcp_bootstream_fops,
+};
+
static int dcp_probe(struct platform_device *pdev)
{
struct dcp *sdcp = NULL;
@@ -1272,6 +1446,7 @@ static int dcp_probe(struct platform_device *pdev)
for (i = 0; i < DCP_NUM_CHANNELS; i++) {
mutex_init(&sdcp->op_mutex[i]);
init_completion(&sdcp->op_wait[i]);
+ sdcp->chan_in_use[i] = false;
}
platform_set_drvdata(pdev, sdcp);
@@ -1282,7 +1457,8 @@ static int dcp_probe(struct platform_device *pdev)
ret = -ENXIO;
goto err_kfree;
}
- sdcp->dcp_regs_base = (u32) IO_ADDRESS(r->start);
+ sdcp->dcp_regs_base = (u32) ioremap(r->start, r->end - r->start + 1);
+ dcp_clock(sdcp, CLOCK_ON, true);
/* Soft reset and remove the clock gate */
__raw_writel(BM_DCP_CTRL_SFTRST, sdcp->dcp_regs_base + HW_DCP_CTRL_SET);
@@ -1318,14 +1494,14 @@ static int dcp_probe(struct platform_device *pdev)
if (!r) {
dev_err(&pdev->dev, "can't get IRQ resource (0)\n");
ret = -EIO;
- goto err_kfree;
+ goto err_gate_clk;
}
sdcp->dcp_vmi_irq = r->start;
ret = request_irq(sdcp->dcp_vmi_irq, dcp_vmi_irq, 0, "dcp",
sdcp);
if (ret != 0) {
dev_err(&pdev->dev, "can't request_irq (0)\n");
- goto err_kfree;
+ goto err_gate_clk;
}
r = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
@@ -1346,7 +1522,7 @@ static int dcp_probe(struct platform_device *pdev)
ret = crypto_register_alg(&dcp_aes_alg);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to register aes crypto\n");
- goto err_kfree;
+ goto err_free_irq1;
}
ret = crypto_register_alg(&dcp_aes_ecb_alg);
@@ -1439,9 +1615,30 @@ static int dcp_probe(struct platform_device *pdev)
}
}
+ /* register dcpboot interface to allow apps (such as kobs-ng) to
+ * verify files (such as the bootstream) using the OTP key for crypto */
+ ret = misc_register(&dcp_bootstream_misc);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Unable to register misc device\n");
+ goto err_unregister_sha1;
+ }
+
+ sdcp->dcpboot_dma_area = dma_alloc_coherent(&pdev->dev,
+ sizeof(*sdcp->dcpboot_dma_area), &sdcp->dcpboot_dma_area_phys,
+ GFP_KERNEL);
+ if (sdcp->dcpboot_dma_area == NULL) {
+ dev_err(&pdev->dev,
+ "Unable to allocate DMAable memory \
+ for dcpboot interface\n");
+ goto err_dereg;
+ }
+
+ dcp_clock(sdcp, CLOCK_OFF, false);
dev_notice(&pdev->dev, "DCP crypto enabled.!\n");
return 0;
+err_dereg:
+ misc_deregister(&dcp_bootstream_misc);
err_unregister_sha1:
crypto_unregister_shash(&dcp_sha1_alg);
err_unregister_aes_cbc:
@@ -1450,8 +1647,12 @@ err_unregister_aes_ecb:
crypto_unregister_alg(&dcp_aes_ecb_alg);
err_unregister_aes:
crypto_unregister_alg(&dcp_aes_alg);
+err_free_irq1:
+ free_irq(sdcp->dcp_irq, sdcp);
err_free_irq0:
free_irq(sdcp->dcp_vmi_irq, sdcp);
+err_gate_clk:
+ dcp_clock(sdcp, CLOCK_OFF, false);
err_kfree:
kfree(sdcp);
err:
@@ -1466,6 +1667,8 @@ static int dcp_remove(struct platform_device *pdev)
sdcp = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
+ dcp_clock(sdcp, CLOCK_ON, false);
+
free_irq(sdcp->dcp_irq, sdcp);
free_irq(sdcp->dcp_vmi_irq, sdcp);
@@ -1487,34 +1690,58 @@ static int dcp_remove(struct platform_device *pdev)
sdcp->user_buf_desc, sdcp->user_buf_desc->my_phys);
}
+ if (sdcp->dcpboot_dma_area) {
+ dma_free_coherent(&pdev->dev, sizeof(*sdcp->dcpboot_dma_area),
+ sdcp->dcpboot_dma_area, sdcp->dcpboot_dma_area_phys);
+ misc_deregister(&dcp_bootstream_misc);
+ }
+
+
crypto_unregister_shash(&dcp_sha1_alg);
- crypto_unregister_shash(&dcp_sha256_alg);
+
+ if (__raw_readl(sdcp->dcp_regs_base + HW_DCP_CAPABILITY1) &
+ BF_DCP_CAPABILITY1_HASH_ALGORITHMS(
+ BV_DCP_CAPABILITY1_HASH_ALGORITHMS__SHA256))
+ crypto_unregister_shash(&dcp_sha256_alg);
crypto_unregister_alg(&dcp_aes_cbc_alg);
crypto_unregister_alg(&dcp_aes_ecb_alg);
crypto_unregister_alg(&dcp_aes_alg);
+
+ dcp_clock(sdcp, CLOCK_OFF, true);
+ iounmap((void *) sdcp->dcp_regs_base);
kfree(sdcp);
global_sdcp = NULL;
return 0;
}
-
-#ifdef CONFIG_PM
static int dcp_suspend(struct platform_device *pdev,
pm_message_t state)
{
+#ifdef CONFIG_PM
+ struct dcp *sdcp = platform_get_drvdata(pdev);
+
+ if (sdcp->clock_state == CLOCK_ON) {
+ dcp_clock(sdcp, CLOCK_OFF, true);
+ /* indicate that clock needs to be turned on upon resume */
+ sdcp->clock_state = CLOCK_ON;
+ }
+#endif
return 0;
}
static int dcp_resume(struct platform_device *pdev)
{
+#ifdef CONFIG_PM
+ struct dcp *sdcp = platform_get_drvdata(pdev);
+
+ /* if clock was on prior to suspend, turn it back on */
+ if (sdcp->clock_state == CLOCK_ON)
+ dcp_clock(sdcp, CLOCK_ON, true);
+#endif
return 0;
}
-#else
-#define dcp_suspend NULL
-#define dcp_resume NULL
-#endif
static struct platform_driver dcp_driver = {
.probe = dcp_probe,
diff --git a/drivers/crypto/dcp.h b/drivers/crypto/dcp.h
index 00cd27b479c0..a4db91334d06 100644
--- a/drivers/crypto/dcp.h
+++ b/drivers/crypto/dcp.h
@@ -19,7 +19,12 @@
#define HASH_CHAN 0
#define HASH_MASK (1 << HASH_CHAN)
-#define ALL_MASK (CIPHER_MASK | HASH_MASK)
+/* DCP boostream interface uses this channel (same as the ROM) */
+#define ROM_DCP_CHAN 3
+#define ROM_DCP_CHAN_MASK (1 << ROM_DCP_CHAN)
+
+
+#define ALL_MASK (CIPHER_MASK | HASH_MASK | ROM_DCP_CHAN_MASK)
/* Defines the initialization value for the dcp control register */
#define DCP_CTRL_INIT \
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 81e1020fb514..27e06ebc2a59 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -89,6 +89,15 @@ config MX3_IPU_IRQS
To avoid bloating the irq_desc[] array we allocate a sufficient
number of IRQ slots and map them dynamically to specific sources.
+config MXC_PXP
+ bool "MXC PxP support"
+ select DMA_ENGINE
+
+config MXC_PXP_CLIENT_DEVICE
+ bool "MXC PxP Client Device"
+ default y
+ depends on MXC_PXP
+
config TXX9_DMAC
tristate "Toshiba TXx9 SoC DMA support"
depends on MACH_TX49XX || MACH_TX39XX
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 40e1e0083571..72c212ac6b79 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_MV_XOR) += mv_xor.o
obj-$(CONFIG_DW_DMAC) += dw_dmac.o
obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
obj-$(CONFIG_MX3_IPU) += ipu/
+obj-$(CONFIG_MXC_PXP) += pxp/
obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index e3235ff8e551..8bb795e7d7b2 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -68,10 +68,19 @@ static u8 *i2c_buf_virt;
static void hw_i2c_dmachan_reset(struct mxs_i2c_dev *dev)
{
+ mxs_dma_disable(dev->dma_chan);
mxs_dma_reset(dev->dma_chan);
mxs_dma_ack_irq(dev->dma_chan);
}
+static mxs_i2c_reset(struct mxs_i2c_dev *mxs_i2c)
+{
+ hw_i2c_dmachan_reset(mxs_i2c);
+ mxs_dma_enable_irq(mxs_i2c->dma_chan, 1);
+ mxs_reset_block((void __iomem *)mxs_i2c->regbase, 0);
+ __raw_writel(0x0000FF00, mxs_i2c->regbase + HW_I2C_CTRL1_SET);
+}
+
static int hw_i2c_dma_init(struct platform_device *pdev)
{
struct mxs_i2c_dev *mxs_i2c = platform_get_drvdata(pdev);
@@ -159,7 +168,7 @@ static void hw_i2c_dma_setup_read(u8 addr, void *buff, int len, int flags)
desc[0]->cmd.cmd.bits.pio_words = 1;
desc[0]->cmd.cmd.bits.wait4end = 1;
desc[0]->cmd.cmd.bits.dec_sem = 1;
- desc[0]->cmd.cmd.bits.irq = 1;
+ desc[0]->cmd.cmd.bits.irq = 0;
desc[0]->cmd.cmd.bits.chain = 1;
desc[0]->cmd.cmd.bits.command = DMA_READ;
desc[0]->cmd.address = i2c_buf_phys;
@@ -319,6 +328,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap,
msecs_to_jiffies(1000)
);
if (err <= 0) {
+ mxs_i2c_reset(dev);
dev_dbg(dev->dev, "controller is timed out\n");
return -ETIMEDOUT;
}
@@ -365,9 +375,19 @@ static irqreturn_t mxs_i2c_dma_isr(int this_irq, void *dev_id)
mxs_dma_ack_irq(mxs_i2c->dma_chan);
mxs_dma_cooked(mxs_i2c->dma_chan, &list);
+ complete(&mxs_i2c->cmd_complete);
+
return IRQ_HANDLED;
}
+static void mxs_i2c_task(struct work_struct *work)
+{
+ struct mxs_i2c_dev *mxs_i2c = container_of(work,
+ struct mxs_i2c_dev, work);
+ mxs_i2c_reset(mxs_i2c);
+ complete(&mxs_i2c->cmd_complete);
+}
+
#define I2C_IRQ_MASK 0x000000FF
static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
{
@@ -382,20 +402,8 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
if (stat & BM_I2C_CTRL1_NO_SLAVE_ACK_IRQ) {
mxs_i2c->cmd_err = -EREMOTEIO;
-
- /*
- * Stop DMA
- * Clear NAK
- */
- __raw_writel(BM_I2C_CTRL1_CLR_GOT_A_NAK,
- mxs_i2c->regbase + HW_I2C_CTRL1_SET);
- hw_i2c_dmachan_reset(mxs_i2c);
- mxs_reset_block((void __iomem *)mxs_i2c->regbase, 1);
- /* Will catch all error (IRQ mask) */
- __raw_writel(0x0000FF00, mxs_i2c->regbase + HW_I2C_CTRL1_SET);
-
- complete(&mxs_i2c->cmd_complete);
-
+ /* it takes long time to reset i2c */
+ schedule_work(&mxs_i2c->work);
goto done;
}
@@ -407,7 +415,10 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
complete(&mxs_i2c->cmd_complete);
goto done;
}
- if ((stat & done_mask) == done_mask)
+
+ if ((stat & done_mask) == done_mask &&
+ (mxs_i2c->flags & MXS_I2C_PIOQUEUE_MODE))
+
complete(&mxs_i2c->cmd_complete);
done:
@@ -524,6 +535,8 @@ static int mxs_i2c_probe(struct platform_device *pdev)
}
+ INIT_WORK(&mxs_i2c->work, mxs_i2c_task);
+
return 0;
no_i2c_adapter:
diff --git a/drivers/i2c/busses/i2c-mxs.h b/drivers/i2c/busses/i2c-mxs.h
index 4ddca007624a..1a35385b793b 100644
--- a/drivers/i2c/busses/i2c-mxs.h
+++ b/drivers/i2c/busses/i2c-mxs.h
@@ -37,5 +37,6 @@ struct mxs_i2c_dev {
struct i2c_adapter adapter;
spinlock_t lock;
wait_queue_head_t queue;
+ struct work_struct work;
};
#endif
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 1148140d08a1..5598ecb48c5b 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -19,6 +19,9 @@
#include <linux/input.h>
#include <linux/major.h>
#include <linux/device.h>
+#ifdef CONFIG_WAKELOCK
+#include <linux/wakelock.h>
+#endif
#include "input-compat.h"
struct evdev {
@@ -42,6 +45,10 @@ struct evdev_client {
struct fasync_struct *fasync;
struct evdev *evdev;
struct list_head node;
+#ifdef CONFIG_WAKELOCK
+ struct wake_lock wake_lock;
+ char name[28];
+#endif
};
static struct evdev *evdev_table[EVDEV_MINORS];
@@ -54,6 +61,9 @@ static void evdev_pass_event(struct evdev_client *client,
* Interrupts are disabled, just acquire the lock
*/
spin_lock(&client->buffer_lock);
+#ifdef CONFIG_WAKELOCK
+ wake_lock_timeout(&client->wake_lock, 5 * HZ);
+#endif
client->buffer[client->head++] = *event;
client->head &= EVDEV_BUFFER_SIZE - 1;
spin_unlock(&client->buffer_lock);
@@ -70,8 +80,15 @@ static void evdev_event(struct input_handle *handle,
struct evdev *evdev = handle->private;
struct evdev_client *client;
struct input_event event;
+#ifdef CONFIG_WAKELOCK
+ struct timespec ts;
+ ktime_get_ts(&ts);
+ event.time.tv_sec = ts.tv_sec;
+ event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+#else
do_gettimeofday(&event.time);
+#endif
event.type = type;
event.code = code;
event.value = value;
@@ -232,6 +249,9 @@ static int evdev_release(struct inode *inode, struct file *file)
mutex_unlock(&evdev->mutex);
evdev_detach_client(evdev, client);
+#ifdef CONFIG_WAKELOCK
+ wake_lock_destroy(&client->wake_lock);
+#endif
kfree(client);
evdev_close_device(evdev);
@@ -268,6 +288,11 @@ static int evdev_open(struct inode *inode, struct file *file)
}
spin_lock_init(&client->buffer_lock);
+#ifdef CONFIG_WAKELOCK
+ snprintf(client->name, sizeof(client->name), "%s-%d", dev_name(&evdev->dev),
+ task_tgid_vnr(current));
+ wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name);
+#endif
client->evdev = evdev;
evdev_attach_client(evdev, client);
@@ -331,6 +356,10 @@ static int evdev_fetch_next_event(struct evdev_client *client,
if (have_event) {
*event = client->buffer[client->tail++];
client->tail &= EVDEV_BUFFER_SIZE - 1;
+#ifdef CONFIG_WAKELOCK
+ if (client->head == client->tail)
+ wake_unlock(&client->wake_lock);
+#endif
}
spin_unlock_irq(&client->buffer_lock);
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index fea01a591076..88e2a24d9cff 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -31,7 +31,7 @@ obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
-obj-$(CONFIG_KEYBOARD_MXC) += mxc_keyb.o
+obj-$(CONFIG_KEYBOARD_MXC) += mxc_keyb.o mxc_pwrkey.o
obj-$(CONFIG_KEYBOARD_MPR084) += mpr084.o
obj-$(CONFIG_KEYBOARD_STMP3XXX) += stmp3xxx-kbd.o
obj-$(CONFIG_KEYBOARD_MXS) += mxs-kbd.o
diff --git a/drivers/input/keyboard/mxc_keyb.c b/drivers/input/keyboard/mxc_keyb.c
index 99dd7cf51cb5..bd5ecd8c20f1 100644
--- a/drivers/input/keyboard/mxc_keyb.c
+++ b/drivers/input/keyboard/mxc_keyb.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -58,12 +58,168 @@
#include <linux/clk.h>
#include <asm/mach/keypad.h>
+/*!
+ * Keypad Module Name
+ */
+#define MOD_NAME "mxckpd"
+
+/*!
+ * XLATE mode selection
+ */
+#define KEYPAD_XLATE 0
+
+/*!
+ * RAW mode selection
+ */
+#define KEYPAD_RAW 1
+
+/*!
+ * Maximum number of keys.
+ */
+#define MAXROW 8
+#define MAXCOL 8
+#define MXC_MAXKEY (MAXROW * MAXCOL)
+
+/*!
+ * This define indicates break scancode for every key release. A constant
+ * of 128 is added to the key press scancode.
+ */
+#define MXC_KEYRELEASE 128
+
+/*
+ * _reg_KPP_KPCR _reg_KPP_KPSR _reg_KPP_KDDR _reg_KPP_KPDR
+ * The offset of Keypad Control Register Address
+ */
+#define KPCR 0x00
+
+/*
+ * The offset of Keypad Status Register Address
+ */
+#define KPSR 0x02
+
+/*
+ * The offset of Keypad Data Direction Address
+ */
+#define KDDR 0x04
+
+/*
+ * The offset of Keypad Data Register
+ */
+#define KPDR 0x06
+
+/*
+ * Key Press Interrupt Status bit
+ */
+#define KBD_STAT_KPKD 0x01
+
+/*
+ * Key Release Interrupt Status bit
+ */
+#define KBD_STAT_KPKR 0x02
+
+/*
+ * Key Depress Synchronizer Chain Status bit
+ */
+#define KBD_STAT_KDSC 0x04
+
+/*
+ * Key Release Synchronizer Status bit
+ */
+#define KBD_STAT_KRSS 0x08
+
+/*
+ * Key Depress Interrupt Enable Status bit
+ */
+#define KBD_STAT_KDIE 0x100
+
/*
- * Module header file
+ * Key Release Interrupt Enable
*/
-#include "mxc_keyb.h"
+#define KBD_STAT_KRIE 0x200
+
+/*
+ * Keypad Clock Enable
+ */
+#define KBD_STAT_KPPEN 0x400
+
+/*!
+ * Buffer size of keypad queue. Should be a power of 2.
+ */
+#define KPP_BUF_SIZE 128
+
+/*!
+ * Test whether bit is set for integer c
+ */
+#define TEST_BIT(c, n) ((c) & (0x1 << (n)))
+
+/*!
+ * Set nth bit in the integer c
+ */
+#define BITSET(c, n) ((c) | (1 << (n)))
+
+/*!
+ * Reset nth bit in the integer c
+ */
+#define BITRESET(c, n) ((c) & ~(1 << (n)))
+
+/*!
+ * This enum represents the keypad state machine to maintain debounce logic
+ * for key press/release.
+ */
+enum KeyState {
+
+ /*!
+ * Key press state.
+ */
+ KStateUp,
+
+ /*!
+ * Key press debounce state.
+ */
+ KStateFirstDown,
+
+ /*!
+ * Key release state.
+ */
+ KStateDown,
+
+ /*!
+ * Key release debounce state.
+ */
+ KStateFirstUp
+};
/*!
+ * Keypad Private Data Structure
+ */
+struct keypad_priv {
+
+ /*!
+ * Keypad state machine.
+ */
+ enum KeyState iKeyState;
+
+ /*!
+ * Number of rows configured in the keypad matrix
+ */
+ unsigned long kpp_rows;
+
+ /*!
+ * Number of Columns configured in the keypad matrix
+ */
+ unsigned long kpp_cols;
+
+ /*!
+ * Timer used for Keypad polling.
+ */
+ struct timer_list poll_timer;
+
+ /*!
+ * The base address
+ */
+ void __iomem *base;
+};
+/*!
* This structure holds the keypad private data structure.
*/
static struct keypad_priv kpp_dev;
@@ -269,26 +425,26 @@ static int mxc_kpp_scan_matrix(void)
for (col = 0; col < kpp_dev.kpp_cols; col++) { /* Col */
/* 2. Write 1.s to KPDR[15:8] setting column data to 1.s */
- reg_val = __raw_readw(KPDR);
+ reg_val = __raw_readw(kpp_dev.base + KPDR);
reg_val |= 0xff00;
- __raw_writew(reg_val, KPDR);
+ __raw_writew(reg_val, kpp_dev.base + KPDR);
/*
* 3. Configure columns as totem pole outputs(for quick
* discharging of keypad capacitance)
*/
- reg_val = __raw_readw(KPCR);
+ reg_val = __raw_readw(kpp_dev.base + KPCR);
reg_val &= 0x00ff;
- __raw_writew(reg_val, KPCR);
+ __raw_writew(reg_val, kpp_dev.base + KPCR);
udelay(2);
/*
* 4. Configure columns as open-drain
*/
- reg_val = __raw_readw(KPCR);
+ reg_val = __raw_readw(kpp_dev.base + KPCR);
reg_val |= ((1 << kpp_dev.kpp_cols) - 1) << 8;
- __raw_writew(reg_val, KPCR);
+ __raw_writew(reg_val, kpp_dev.base + KPCR);
/*
* 5. Write a single column to 0, others to 1.
@@ -298,9 +454,9 @@ static int mxc_kpp_scan_matrix(void)
*/
/* Col bit starts at 8th bit in KPDR */
- reg_val = __raw_readw(KPDR);
+ reg_val = __raw_readw(kpp_dev.base + KPDR);
reg_val &= ~(1 << (8 + col));
- __raw_writew(reg_val, KPDR);
+ __raw_writew(reg_val, kpp_dev.base + KPDR);
/* Delay added to avoid propagating the 0 from column to row
* when scanning. */
@@ -308,7 +464,7 @@ static int mxc_kpp_scan_matrix(void)
udelay(5);
/* Read row input */
- reg_val = __raw_readw(KPDR);
+ reg_val = __raw_readw(kpp_dev.base + KPDR);
for (row = 0; row < kpp_dev.kpp_rows; row++) { /* sample row */
if (TEST_BIT(reg_val, row) == 0) {
cur_rcmap[row] = BITSET(cur_rcmap[row], col);
@@ -324,12 +480,12 @@ static int mxc_kpp_scan_matrix(void)
* clear the KPKD synchronizer chain by writing "1" to KDSC register
*/
reg_val = 0x00;
- __raw_writew(reg_val, KPDR);
- reg_val = __raw_readw(KPDR);
- reg_val = __raw_readw(KPSR);
+ __raw_writew(reg_val, kpp_dev.base + KPDR);
+ reg_val = __raw_readw(kpp_dev.base + KPDR);
+ reg_val = __raw_readw(kpp_dev.base + KPSR);
reg_val |= KBD_STAT_KPKD | KBD_STAT_KPKR | KBD_STAT_KRSS |
KBD_STAT_KDSC;
- __raw_writew(reg_val, KPSR);
+ __raw_writew(reg_val, kpp_dev.base + KPSR);
/* Check key press status change */
@@ -558,14 +714,14 @@ static void mxc_kpp_handle_timer(unsigned long data)
* Stop scanning and wait for interrupt.
* Enable press interrupt and disable release interrupt.
*/
- __raw_writew(0x00FF, KPDR);
- reg_val = __raw_readw(KPSR);
+ __raw_writew(0x00FF, kpp_dev.base + KPDR);
+ reg_val = __raw_readw(kpp_dev.base + KPSR);
reg_val |= (KBD_STAT_KPKR | KBD_STAT_KPKD);
reg_val |= KBD_STAT_KRSS | KBD_STAT_KDSC;
- __raw_writew(reg_val, KPSR);
+ __raw_writew(reg_val, kpp_dev.base + KPSR);
reg_val |= KBD_STAT_KDIE;
reg_val &= ~KBD_STAT_KRIE;
- __raw_writew(reg_val, KPSR);
+ __raw_writew(reg_val, kpp_dev.base + KPSR);
/*
* No more keys pressed... make sure unwanted key codes are
@@ -613,7 +769,7 @@ static irqreturn_t mxc_kpp_interrupt(int irq, void *dev_id)
/* Delete the polling timer */
del_timer(&kpp_dev.poll_timer);
- reg_val = __raw_readw(KPSR);
+ reg_val = __raw_readw(kpp_dev.base + KPSR);
/* Check if it is key press interrupt */
if (reg_val & KBD_STAT_KPKD) {
@@ -621,7 +777,7 @@ static irqreturn_t mxc_kpp_interrupt(int irq, void *dev_id)
* Disable key press(KDIE status bit) interrupt
*/
reg_val &= ~KBD_STAT_KDIE;
- __raw_writew(reg_val, KPSR);
+ __raw_writew(reg_val, kpp_dev.base + KPSR);
} else {
/* spurious interrupt */
return IRQ_RETVAL(0);
@@ -767,6 +923,7 @@ static int mxc_kpp_probe(struct platform_device *pdev)
int i, irq;
int retval;
unsigned int reg_val;
+ struct resource *res;
keypad = (struct keypad_data *)pdev->dev.platform_data;
@@ -774,6 +931,14 @@ static int mxc_kpp_probe(struct platform_device *pdev)
kpp_dev.kpp_rows = keypad->rowmax;
key_pad_enabled = 0;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ kpp_dev.base = ioremap(res->start, res->end - res->start + 1);
+ if (!kpp_dev.base)
+ return -ENOMEM;
+
irq = platform_get_irq(pdev, 0);
keypad->irq = irq;
@@ -793,30 +958,30 @@ static int mxc_kpp_probe(struct platform_device *pdev)
* LSB nibble in KPP is for 8 rows
* MSB nibble in KPP is for 8 cols
*/
- reg_val = __raw_readw(KPCR);
+ reg_val = __raw_readw(kpp_dev.base + KPCR);
reg_val |= (1 << keypad->rowmax) - 1; /* LSB */
reg_val |= ((1 << keypad->colmax) - 1) << 8; /* MSB */
- __raw_writew(reg_val, KPCR);
+ __raw_writew(reg_val, kpp_dev.base + KPCR);
/* Write 0's to KPDR[15:8] */
- reg_val = __raw_readw(KPDR);
+ reg_val = __raw_readw(kpp_dev.base + KPDR);
reg_val &= 0x00ff;
- __raw_writew(reg_val, KPDR);
+ __raw_writew(reg_val, kpp_dev.base + KPDR);
/* Configure columns as output, rows as input (KDDR[15:0]) */
- reg_val = __raw_readw(KDDR);
+ reg_val = __raw_readw(kpp_dev.base + KDDR);
reg_val |= 0xff00;
reg_val &= 0xff00;
- __raw_writew(reg_val, KDDR);
+ __raw_writew(reg_val, kpp_dev.base + KDDR);
- reg_val = __raw_readw(KPSR);
+ reg_val = __raw_readw(kpp_dev.base + KPSR);
reg_val &= ~(KBD_STAT_KPKR | KBD_STAT_KPKD);
reg_val |= KBD_STAT_KPKD;
reg_val |= KBD_STAT_KRSS | KBD_STAT_KDSC;
- __raw_writew(reg_val, KPSR);
+ __raw_writew(reg_val, kpp_dev.base + KPSR);
reg_val |= KBD_STAT_KDIE;
reg_val &= ~KBD_STAT_KRIE;
- __raw_writew(reg_val, KPSR);
+ __raw_writew(reg_val, kpp_dev.base + KPSR);
has_leaning_key = keypad->learning;
mxckpd_keycodes = keypad->matrix;
@@ -912,7 +1077,7 @@ static int mxc_kpp_probe(struct platform_device *pdev)
retval = request_irq(irq, mxc_kpp_interrupt, 0, MOD_NAME, MOD_NAME);
if (retval) {
pr_debug("KPP: request_irq(%d) returned error %d\n",
- MXC_INT_KPP, retval);
+ irq, retval);
goto err3;
}
@@ -950,16 +1115,16 @@ static int mxc_kpp_remove(struct platform_device *pdev)
* Set KDIE control bit, clear KRIE control bit (avoid false release
* events. Disable the keypad GPIO pins.
*/
- __raw_writew(0x00, KPCR);
- __raw_writew(0x00, KPDR);
- __raw_writew(0x00, KDDR);
+ __raw_writew(0x00, kpp_dev.base + KPCR);
+ __raw_writew(0x00, kpp_dev.base + KPDR);
+ __raw_writew(0x00, kpp_dev.base + KDDR);
- reg_val = __raw_readw(KPSR);
+ reg_val = __raw_readw(kpp_dev.base + KPSR);
reg_val |= KBD_STAT_KPKD;
reg_val &= ~KBD_STAT_KRSS;
reg_val |= KBD_STAT_KDIE;
reg_val &= ~KBD_STAT_KRIE;
- __raw_writew(reg_val, KPSR);
+ __raw_writew(reg_val, kpp_dev.base + KPSR);
gpio_keypad_inactive();
clk_disable(kpp_clk);
diff --git a/drivers/input/misc/mma7455l.c b/drivers/input/misc/mma7455l.c
index 1cee2d1add04..48dca60d2cfe 100644
--- a/drivers/input/misc/mma7455l.c
+++ b/drivers/input/misc/mma7455l.c
@@ -583,6 +583,8 @@ static int __devexit mma7455l_remove(struct i2c_client *client)
{
struct mma7455l_info *mma = dev_get_drvdata(&client->dev);
+ free_irq(client->irq, mma);
+
sysfs_remove_group(&client->dev.kobj, &mma7455l_attr_group);
input_unregister_device(mma->input_dev);
dev_set_drvdata(&client->dev, NULL);
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index ba9d38c3f412..0f74aeee2aea 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -17,14 +17,11 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <linux/hwmon.h>
+#include <linux/device.h>
#include <linux/init.h>
-#include <linux/err.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <asm/irq.h>
@@ -33,9 +30,7 @@
/*
* This code has been heavily tested on a Nokia 770, and lightly
* tested on other ads7846 devices (OSK/Mistral, Lubbock).
- * TSC2046 is just newer ads7846 silicon.
- * Support for ads7843 tested on Atmel at91sam926x-EK.
- * Support for ads7845 has only been stubbed in.
+ * Support for ads7843 and ads7845 has only been stubbed in.
*
* IRQ handling needs a workaround because of a shortcoming in handling
* edge triggered IRQs on some platforms like the OMAP1/2. These
@@ -51,8 +46,7 @@
* files.
*/
-#define TS_POLL_DELAY (1 * 1000000) /* ns delay before the first sample */
-#define TS_POLL_PERIOD (5 * 1000000) /* ns delay between samples */
+#define TS_POLL_PERIOD msecs_to_jiffies(10)
/* this driver doesn't aim at the peak continuous sample rate */
#define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
@@ -61,77 +55,57 @@ struct ts_event {
/* For portability, we can't read 12 bit values using SPI (which
* would make the controller deliver them as native byteorder u16
* with msbs zeroed). Instead, we read them as two 8-bit values,
- * *** WHICH NEED BYTESWAPPING *** and range adjustment.
+ * which need byteswapping then range adjustment.
*/
- u16 x;
- u16 y;
- u16 z1, z2;
- int ignore;
-};
-
-/*
- * We allocate this separately to avoid cache line sharing issues when
- * driver is used with DMA-based SPI controllers (like atmel_spi) on
- * systems where main memory is not DMA-coherent (most non-x86 boards).
- */
-struct ads7846_packet {
- u8 read_x, read_y, read_z1, read_z2, pwrdown;
- u16 dummy; /* for the pwrdown read */
- struct ts_event tc;
+ __be16 x;
+ __be16 y;
+ __be16 z1, z2;
+ int ignore;
};
struct ads7846 {
struct input_dev *input;
char phys[32];
- char name[32];
- struct spi_device *spi;
-
-#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
- struct attribute_group *attr_group;
- struct device *hwmon;
-#endif
+ u32 *txbuf;
+ u32 *rxbuf;
+ u8 buflen;
+ u8 skip_samples;
+ u16 rotate;
+ struct spi_device *spi;
u16 model;
- u16 vref_mv;
u16 vref_delay_usecs;
u16 x_plate_ohms;
u16 pressure_max;
- bool swap_xy;
-
- struct ads7846_packet *packet;
+ u8 read_x, read_y, read_z1, read_z2, pwrdown;
+ u16 zerro; /* to send zerros while receiving */
+ u16 dummy; /* for the pwrdown read */
+ struct ts_event tc;
- struct spi_transfer xfer[18];
+ struct spi_transfer xfer[10];
struct spi_message msg[5];
struct spi_message *last_msg;
int msg_idx;
int read_cnt;
int read_rep;
int last_read;
+ int skip_this_sample;
u16 debounce_max;
u16 debounce_tol;
u16 debounce_rep;
- u16 penirq_recheck_delay_usecs;
-
spinlock_t lock;
- struct hrtimer timer;
+ struct timer_list timer; /* P: lock */
unsigned pendown:1; /* P: lock */
unsigned pending:1; /* P: lock */
// FIXME remove "irq_disabled"
unsigned irq_disabled:1; /* P: lock */
unsigned disabled:1;
- unsigned is_suspended:1;
- int (*filter)(void *data, int data_idx, int *val);
- void *filter_data;
- void (*filter_cleanup)(void *data);
int (*get_pendown_state)(void);
- int gpio_pendown;
-
- void (*wait_for_sync)(void);
};
/* leave chip selected when we're done, for quicker re-select? */
@@ -141,6 +115,7 @@ struct ads7846 {
#define CS_CHANGE(xfer) ((xfer).cs_change = 0)
#endif
+
/*--------------------------------------------------------------------------*/
/* The ADS7846 has touchscreen and other sensors.
@@ -167,16 +142,19 @@ struct ads7846 {
#define MAX_12BIT ((1<<12)-1)
/* leave ADC powered up (disables penirq) between differential samples */
-#define READ_12BIT_DFR(x, adc, vref) (ADS_START | ADS_A2A1A0_d_ ## x \
- | ADS_12_BIT | ADS_DFR | \
- (adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0))
+#define READ_12BIT_DFR(x) (ADS_START | ADS_A2A1A0_d_ ## x \
+ | ADS_12_BIT | ADS_DFR)
+
+#define READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ADC_ON)
+#define READ_Z1 (READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON)
+#define READ_Z2 (READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON)
-#define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref))
-#define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref))
-#define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref))
+#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_ADC_ON)
+#define PWRDOWN (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) /* LAST */
-#define READ_X(vref) (READ_12BIT_DFR(x, 1, vref))
-#define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */
+/* alternate ads7843 commands */
+#define ALT_READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ALL_ON)
+#define ALT_READ_X (READ_12BIT_DFR(x) | ADS_PD10_ALL_ON)
/* single-ended samples need to first power up reference voltage;
* we leave both ADC and VREF powered
@@ -184,15 +162,21 @@ struct ads7846 {
#define READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \
| ADS_12_BIT | ADS_SER)
-#define REF_ON (READ_12BIT_DFR(x, 1, 1))
-#define REF_OFF (READ_12BIT_DFR(y, 0, 0))
+#define REF_ON (READ_12BIT_DFR(x) | ADS_PD10_ALL_ON)
+#define REF_OFF (READ_12BIT_DFR(y) | ADS_PD10_PDOWN)
+
+#define MAX_BUF_SAMPLE_LEN (20)
+/* Following configuration should be done in the platform configuration */
+#define SCREEN_LANDSCAPE 1
+#undef SCREEN_PORTRAIT
+#define MAX_DIFF_BETWEEN_SAMPLES_X 100
+#define MAX_DIFF_BETWEEN_SAMPLES_Y 100
+
/*--------------------------------------------------------------------------*/
/*
* Non-touchscreen sensors only use single-ended conversions.
- * The range is GND..vREF. The ads7843 and ads7835 must use external vREF;
- * ads7846 lets that pin be unconnected, to use internal vREF.
*/
struct ser_req {
@@ -200,6 +184,7 @@ struct ser_req {
u8 command;
u8 ref_off;
u16 scratch;
+ u16 zerro;
__be16 sample;
struct spi_message msg;
struct spi_transfer xfer[6];
@@ -211,247 +196,132 @@ static void ads7846_disable(struct ads7846 *ts);
static int device_suspended(struct device *dev)
{
struct ads7846 *ts = dev_get_drvdata(dev);
- return ts->is_suspended || ts->disabled;
+ return dev->power.power_state.event != PM_EVENT_ON || ts->disabled;
}
+static int ads7843_setup_buffers(struct device *dev)
+{
+ struct ads7846 *ts = dev_get_drvdata(dev);
+ int i;
+
+ ts->txbuf = kzalloc(sizeof(u32) * ts->buflen * 3, GFP_KERNEL);
+ if (!ts->txbuf)
+ return -ENOMEM;
+
+ ts->rxbuf = kzalloc(sizeof(u32) * ts->buflen * 3, GFP_KERNEL);
+ if (!ts->rxbuf) {
+ kfree(ts->txbuf);
+ return -ENOMEM;
+ }
+ for (i = 0; i < ((ts->buflen * 3) / 2); i++)
+#if defined( SCREEN_LANDSCAPE )
+ ts->txbuf[i] = (READ_12BIT_DFR(x) | ADS_PD10_PDOWN) << 8;
+#else
+ ts->txbuf[i] = (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) << 8;
+#endif
+ for (; i < ts->buflen * 3; i++)
+#if defined( SCREEN_LANDSCAPE )
+ ts->txbuf[i] = (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) << 8;
+#else
+ ts->txbuf[i] = (READ_12BIT_DFR(x) | ADS_PD10_PDOWN) << 8;
+#endif
+ return 0;
+}
+
+
static int ads7846_read12_ser(struct device *dev, unsigned command)
{
struct spi_device *spi = to_spi_device(dev);
struct ads7846 *ts = dev_get_drvdata(dev);
struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
int status;
- int use_internal;
+ int sample;
+ int i;
if (!req)
return -ENOMEM;
spi_message_init(&req->msg);
- /* FIXME boards with ads7846 might use external vref instead ... */
- use_internal = (ts->model == 7846);
-
- /* maybe turn on internal vREF, and let it settle */
- if (use_internal) {
- req->ref_on = REF_ON;
- req->xfer[0].tx_buf = &req->ref_on;
- req->xfer[0].len = 1;
- spi_message_add_tail(&req->xfer[0], &req->msg);
-
- req->xfer[1].rx_buf = &req->scratch;
- req->xfer[1].len = 2;
-
- /* for 1uF, settle for 800 usec; no cap, 100 usec. */
- req->xfer[1].delay_usecs = ts->vref_delay_usecs;
- spi_message_add_tail(&req->xfer[1], &req->msg);
- }
+ /* activate reference, so it has time to settle; */
+ req->ref_on = REF_ON;
+ req->xfer[0].tx_buf = &req->ref_on;
+ req->xfer[0].len = 1;
+ req->xfer[1].tx_buf = &req->zerro;
+ req->xfer[1].rx_buf = &req->scratch;
+ req->xfer[1].len = 2;
+
+ /*
+ * for external VREF, 0 usec (and assume it's always on);
+ * for 1uF, use 800 usec;
+ * no cap, 100 usec.
+ */
+ req->xfer[1].delay_usecs = ts->vref_delay_usecs;
/* take sample */
req->command = (u8) command;
req->xfer[2].tx_buf = &req->command;
req->xfer[2].len = 1;
- spi_message_add_tail(&req->xfer[2], &req->msg);
-
+ req->xfer[3].tx_buf = &req->zerro;
req->xfer[3].rx_buf = &req->sample;
req->xfer[3].len = 2;
- spi_message_add_tail(&req->xfer[3], &req->msg);
/* REVISIT: take a few more samples, and compare ... */
- /* converter in low power mode & enable PENIRQ */
- req->ref_off = PWRDOWN;
+ /* turn off reference */
+ req->ref_off = REF_OFF;
req->xfer[4].tx_buf = &req->ref_off;
req->xfer[4].len = 1;
- spi_message_add_tail(&req->xfer[4], &req->msg);
-
+ // TODO req->xfer[3].tx_buf = &req->zerro;
+ req->xfer[5].tx_buf = &req->zerro;
req->xfer[5].rx_buf = &req->scratch;
req->xfer[5].len = 2;
+
CS_CHANGE(req->xfer[5]);
- spi_message_add_tail(&req->xfer[5], &req->msg);
+
+ /* group all the transfers together, so we can't interfere with
+ * reading touchscreen state; disable penirq while sampling
+ */
+ for (i = 0; i < 6; i++)
+ spi_message_add_tail(&req->xfer[i], &req->msg);
ts->irq_disabled = 1;
- disable_irq(spi->irq);
+ disable_irq_nosync(spi->irq);
status = spi_sync(spi, &req->msg);
ts->irq_disabled = 0;
enable_irq(spi->irq);
- if (status == 0) {
- /* on-wire is a must-ignore bit, a BE12 value, then padding */
- status = be16_to_cpu(req->sample);
- status = status >> 3;
- status &= 0x0fff;
- }
+ if (req->msg.status)
+ status = req->msg.status;
+
+ /* on-wire is a must-ignore bit, a BE12 value, then padding */
+ sample = be16_to_cpu(req->sample);
+ sample = sample >> 3;
+ sample &= 0x0fff;
kfree(req);
- return status;
+ return status ? status : sample;
}
-#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
-
-#define SHOW(name, var, adjust) static ssize_t \
+#define SHOW(name) static ssize_t \
name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
- struct ads7846 *ts = dev_get_drvdata(dev); \
ssize_t v = ads7846_read12_ser(dev, \
- READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \
+ READ_12BIT_SER(name) | ADS_PD10_ALL_ON); \
if (v < 0) \
return v; \
- return sprintf(buf, "%u\n", adjust(ts, v)); \
+ return sprintf(buf, "%u\n", (unsigned) v); \
} \
static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
-
-/* Sysfs conventions report temperatures in millidegrees Celsius.
- * ADS7846 could use the low-accuracy two-sample scheme, but can't do the high
- * accuracy scheme without calibration data. For now we won't try either;
- * userspace sees raw sensor values, and must scale/calibrate appropriately.
- */
-static inline unsigned null_adjust(struct ads7846 *ts, ssize_t v)
-{
- return v;
-}
-
-SHOW(temp0, temp0, null_adjust) /* temp1_input */
-SHOW(temp1, temp1, null_adjust) /* temp2_input */
-
-
-/* sysfs conventions report voltages in millivolts. We can convert voltages
- * if we know vREF. userspace may need to scale vAUX to match the board's
- * external resistors; we assume that vBATT only uses the internal ones.
- */
-static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
-{
- unsigned retval = v;
-
- /* external resistors may scale vAUX into 0..vREF */
- retval *= ts->vref_mv;
- retval = retval >> 12;
- return retval;
-}
-
-static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)
-{
- unsigned retval = vaux_adjust(ts, v);
-
- /* ads7846 has a resistor ladder to scale this signal down */
- if (ts->model == 7846)
- retval *= 4;
- return retval;
-}
-
-SHOW(in0_input, vaux, vaux_adjust)
-SHOW(in1_input, vbatt, vbatt_adjust)
-
-
-static struct attribute *ads7846_attributes[] = {
- &dev_attr_temp0.attr,
- &dev_attr_temp1.attr,
- &dev_attr_in0_input.attr,
- &dev_attr_in1_input.attr,
- NULL,
-};
-
-static struct attribute_group ads7846_attr_group = {
- .attrs = ads7846_attributes,
-};
-
-static struct attribute *ads7843_attributes[] = {
- &dev_attr_in0_input.attr,
- &dev_attr_in1_input.attr,
- NULL,
-};
-
-static struct attribute_group ads7843_attr_group = {
- .attrs = ads7843_attributes,
-};
-
-static struct attribute *ads7845_attributes[] = {
- &dev_attr_in0_input.attr,
- NULL,
-};
-
-static struct attribute_group ads7845_attr_group = {
- .attrs = ads7845_attributes,
-};
-
-static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
-{
- struct device *hwmon;
- int err;
-
- /* hwmon sensors need a reference voltage */
- switch (ts->model) {
- case 7846:
- if (!ts->vref_mv) {
- dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n");
- ts->vref_mv = 2500;
- }
- break;
- case 7845:
- case 7843:
- if (!ts->vref_mv) {
- dev_warn(&spi->dev,
- "external vREF for ADS%d not specified\n",
- ts->model);
- return 0;
- }
- break;
- }
-
- /* different chips have different sensor groups */
- switch (ts->model) {
- case 7846:
- ts->attr_group = &ads7846_attr_group;
- break;
- case 7845:
- ts->attr_group = &ads7845_attr_group;
- break;
- case 7843:
- ts->attr_group = &ads7843_attr_group;
- break;
- default:
- dev_dbg(&spi->dev, "ADS%d not recognized\n", ts->model);
- return 0;
- }
-
- err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
- if (err)
- return err;
-
- hwmon = hwmon_device_register(&spi->dev);
- if (IS_ERR(hwmon)) {
- sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
- return PTR_ERR(hwmon);
- }
-
- ts->hwmon = hwmon;
- return 0;
-}
-
-static void ads784x_hwmon_unregister(struct spi_device *spi,
- struct ads7846 *ts)
-{
- if (ts->hwmon) {
- sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
- hwmon_device_unregister(ts->hwmon);
- }
-}
-
-#else
-static inline int ads784x_hwmon_register(struct spi_device *spi,
- struct ads7846 *ts)
-{
- return 0;
-}
-
-static inline void ads784x_hwmon_unregister(struct spi_device *spi,
- struct ads7846 *ts)
-{
-}
-#endif
+SHOW(temp0)
+SHOW(temp1)
+SHOW(vaux)
+SHOW(vbatt)
static int is_pen_down(struct device *dev)
{
- struct ads7846 *ts = dev_get_drvdata(dev);
+ struct ads7846 *ts = dev_get_drvdata(dev);
return ts->pendown;
}
@@ -477,11 +347,10 @@ static ssize_t ads7846_disable_store(struct device *dev,
const char *buf, size_t count)
{
struct ads7846 *ts = dev_get_drvdata(dev);
- unsigned long i;
-
- if (strict_strtoul(buf, 10, &i))
- return -EINVAL;
+ char *endp;
+ int i;
+ i = simple_strtoul(buf, &endp, 10);
spin_lock_irq(&ts->lock);
if (i)
@@ -496,30 +365,8 @@ static ssize_t ads7846_disable_store(struct device *dev,
static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store);
-static struct attribute *ads784x_attributes[] = {
- &dev_attr_pen_down.attr,
- &dev_attr_disable.attr,
- NULL,
-};
-
-static struct attribute_group ads784x_attr_group = {
- .attrs = ads784x_attributes,
-};
-
/*--------------------------------------------------------------------------*/
-static int get_pendown_state(struct ads7846 *ts)
-{
- if (ts->get_pendown_state)
- return ts->get_pendown_state();
-
- return !gpio_get_value(ts->gpio_pendown);
-}
-
-static void null_wait_for_sync(void)
-{
-}
-
/*
* PENIRQ only kicks the timer. The timer only reissues the SPI transfer,
* to retrieve touchscreen status.
@@ -531,25 +378,25 @@ static void null_wait_for_sync(void)
static void ads7846_rx(void *ads)
{
struct ads7846 *ts = ads;
- struct ads7846_packet *packet = ts->packet;
+ struct input_dev *input_dev = ts->input;
unsigned Rt;
+ unsigned sync = 0;
u16 x, y, z1, z2;
+ unsigned long flags;
- /* ads7846_rx_val() did in-place conversion (including byteswap) from
- * on-the-wire format as part of debouncing to get stable readings.
+ /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding;
+ * built from two 8 bit values written msb-first.
*/
- x = packet->tc.x;
- y = packet->tc.y;
- z1 = packet->tc.z1;
- z2 = packet->tc.z2;
+ x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff;
+ y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff;
+ z1 = (be16_to_cpu(ts->tc.z1) >> 3) & 0x0fff;
+ z2 = (be16_to_cpu(ts->tc.z2) >> 3) & 0x0fff;
/* range filtering */
if (x == MAX_12BIT)
x = 0;
- if (ts->model == 7843) {
- Rt = ts->pressure_max / 2;
- } else if (likely(x && z1)) {
+ if (likely(x && z1 && !device_suspended(&ts->spi->dev))) {
/* compute touch pressure resistance using equation #2 */
Rt = z2;
Rt -= z1;
@@ -557,194 +404,281 @@ static void ads7846_rx(void *ads)
Rt *= ts->x_plate_ohms;
Rt /= z1;
Rt = (Rt + 2047) >> 12;
- } else {
+ } else
Rt = 0;
- }
/* Sample found inconsistent by debouncing or pressure is beyond
- * the maximum. Don't report it to user space, repeat at least
- * once more the measurement
- */
- if (packet->tc.ignore || Rt > ts->pressure_max) {
-#ifdef VERBOSE
- pr_debug("%s: ignored %d pressure %d\n",
- dev_name(&ts->spi->dev), packet->tc.ignore, Rt);
-#endif
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
- HRTIMER_MODE_REL);
+ * the maximum. Don't report it to user space, repeat at least
+ * once more the measurement */
+ if (ts->tc.ignore || Rt > ts->pressure_max) {
+ mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
return;
}
- /* Maybe check the pendown state before reporting. This discards
- * false readings when the pen is lifted.
+ /* NOTE: "pendown" is inferred from pressure; we don't rely on
+ * being able to check nPENIRQ status, or "friendly" trigger modes
+ * (both-edges is much better than just-falling or low-level).
+ *
+ * REVISIT: some boards may require reading nPENIRQ; it's
+ * needed on 7843. and 7845 reads pressure differently...
+ *
+ * REVISIT: the touchscreen might not be connected; this code
+ * won't notice that, even if nPENIRQ never fires ...
*/
- if (ts->penirq_recheck_delay_usecs) {
- udelay(ts->penirq_recheck_delay_usecs);
- if (!get_pendown_state(ts))
- Rt = 0;
+ if (!ts->pendown && Rt != 0) {
+ input_report_key(input_dev, BTN_TOUCH, 1);
+ sync = 1;
+ } else if (ts->pendown && Rt == 0) {
+ input_report_key(input_dev, BTN_TOUCH, 0);
+ sync = 1;
}
- /* NOTE: We can't rely on the pressure to determine the pen down
- * state, even this controller has a pressure sensor. The pressure
- * value can fluctuate for quite a while after lifting the pen and
- * in some cases may not even settle at the expected value.
- *
- * The only safe way to check for the pen up condition is in the
- * timer by reading the pen signal state (it's a GPIO _and_ IRQ).
- */
if (Rt) {
- struct input_dev *input = ts->input;
+ input_report_abs(input_dev, ABS_X, x);
+ input_report_abs(input_dev, ABS_Y, y);
+ sync = 1;
+ }
- if (!ts->pendown) {
- input_report_key(input, BTN_TOUCH, 1);
- ts->pendown = 1;
-#ifdef VERBOSE
- dev_dbg(&ts->spi->dev, "DOWN\n");
+ if (sync) {
+ input_report_abs(input_dev, ABS_PRESSURE, Rt);
+ input_sync(input_dev);
+ }
+
+#ifdef VERBOSE
+ if (Rt || ts->pendown)
+ pr_debug("%s: %d/%d/%d%s\n", dev_name(&ts->spi->dev),
+ x, y, Rt, Rt ? "" : " UP");
#endif
+
+ spin_lock_irqsave(&ts->lock, flags);
+
+ ts->pendown = (Rt != 0);
+ mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+
+ spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static inline u16 ad7843_get_sample_val(u32 sample)
+{
+ return (((((sample & 0x00ff0000) >> 8) | (sample >> 24)) >> 3) & 0x0fff);
+}
+
+static u32 ad7843_get_better_values(struct ads7846 *ts, int index, int skiplimit)
+{
+ u32 diff12, diff23, diff31;
+ u32 vals[3];
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ vals[i] = ad7843_get_sample_val(ts->rxbuf[index+i]);
+ if (vals[i] == 0x0fff || vals[i] == 0) {
+ ts->skip_this_sample = 1;
+ return 0;
}
+ }
- if (ts->swap_xy)
- swap(x, y);
+ diff12 = (vals[0] > vals[1]) ? vals[0] - vals[1] : vals[1] - vals[0];
+ if (diff12 > skiplimit) {
+ ts->skip_this_sample = 1;
+ return 0;
+ }
- input_report_abs(input, ABS_X, x);
- input_report_abs(input, ABS_Y, y);
- input_report_abs(input, ABS_PRESSURE, Rt);
+ diff23 = (vals[1] > vals[2]) ? vals[1] - vals[2] : vals[2] - vals[1];
+ if (diff23 > skiplimit) {
+ ts->skip_this_sample = 1;
+ return 0;
+ }
- input_sync(input);
-#ifdef VERBOSE
- dev_dbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
-#endif
+ diff31 = (vals[2] > vals[0]) ? vals[2] - vals[0] : vals[0] - vals[2];
+ if (diff31 > skiplimit) {
+ ts->skip_this_sample = 1;
+ return 0;
}
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
- HRTIMER_MODE_REL);
+ if (diff12 < diff23 && diff12 < diff31)
+ return (vals[0] + vals[1]) / 2;
+ if (diff23 < diff12 && diff23 < diff31)
+ return (vals[1] + vals[2]) / 2;
+
+ return (vals[0] + vals[2]) / 2;
}
-static int ads7846_debounce(void *ads, int data_idx, int *val)
+static void ads7843_rx_average(void *ads)
+{
+ struct ads7846 *ts = ads;
+ struct input_dev *input_dev = ts->input;
+ u16 x, y, temp;
+ unsigned long flags;
+ int i, sample_count;
+
+ dev_dbg(&ts->spi->dev, "%s\n", __FUNCTION__);
+
+ for (i = 0, y = 0, x = 0, sample_count = 0; i < (ts->buflen * 3 / 2); i+=3) {
+ if (i >= ts->skip_samples*3) {
+ temp = ad7843_get_better_values(ts, i, MAX_DIFF_BETWEEN_SAMPLES_Y);
+ if (!ts->skip_this_sample) {
+ if (ts->rotate == 180) {
+ y += MAX_12BIT - temp;
+ } else if (ts->rotate == 0) {
+ y += temp;
+ } else {
+ dev_info(&ts->spi->dev,
+ "Rotate mode %d, not implemented yet\n",
+ ts->rotate);
+ }
+ sample_count++;
+ }
+ }
+ ts->skip_this_sample = 0;
+ }
+
+ if (!sample_count)
+ goto sample_taken;
+
+ y /= sample_count;
+
+ for (sample_count = 0; i < (ts->buflen * 3); i+=3) {
+ if (i >= (ts->skip_samples + ts->buflen / 2)*3) {
+ temp = ad7843_get_better_values(ts, i, MAX_DIFF_BETWEEN_SAMPLES_X);
+ if (!ts->skip_this_sample) {
+ if (ts->rotate == 180) {
+ x += MAX_12BIT - temp;
+ } else if (ts->rotate == 0) {
+ x += temp;
+ } else {
+ dev_info(&ts->spi->dev,
+ "Rotate mode %d, not implemented yet\n",
+ ts->rotate);
+ }
+ sample_count++;
+ }
+ }
+ ts->skip_this_sample = 0;
+ }
+
+ if (!sample_count)
+ goto sample_taken;
+
+ x /= sample_count;
+
+ if (ts->pendown) {
+
+ input_report_key(input_dev, BTN_TOUCH, 1);
+ input_report_abs(input_dev, ABS_PRESSURE, ts->pressure_max / 2);
+ input_report_abs(input_dev, ABS_X, x);
+ input_report_abs(input_dev, ABS_Y, y);
+ } else {
+ input_report_key(input_dev, BTN_TOUCH, 0);
+ input_report_abs(input_dev, ABS_PRESSURE, 0);
+ }
+
+ input_sync(input_dev);
+ dev_dbg(&ts->spi->dev, "%d/%d %s\n", x, y, ts->pendown ? "" : " UP");
+
+sample_taken:
+ if (ts->pendown) {
+ spin_lock_irqsave(&ts->lock, flags);
+ mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+ spin_unlock_irqrestore(&ts->lock, flags);
+ }
+}
+
+static void ads7846_debounce(void *ads)
{
struct ads7846 *ts = ads;
+ struct spi_message *m;
+ struct spi_transfer *t;
+ int val;
+ int status;
- if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
- /* Start over collecting consistent readings. */
- ts->read_rep = 0;
+ m = &ts->msg[ts->msg_idx];
+ t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+ val = (be16_to_cpu(*(__be16 *)t->rx_buf) >> 3) & 0x0fff;
+ if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) {
/* Repeat it, if this was the first read or the read
* wasn't consistent enough. */
if (ts->read_cnt < ts->debounce_max) {
- ts->last_read = *val;
+ ts->last_read = val;
ts->read_cnt++;
- return ADS7846_FILTER_REPEAT;
} else {
/* Maximum number of debouncing reached and still
* not enough number of consistent readings. Abort
* the whole sample, repeat it in the next sampling
* period.
*/
+ ts->tc.ignore = 1;
ts->read_cnt = 0;
- return ADS7846_FILTER_IGNORE;
+ /* Last message will contain ads7846_rx() as the
+ * completion function.
+ */
+ m = ts->last_msg;
}
+ /* Start over collecting consistent readings. */
+ ts->read_rep = 0;
} else {
if (++ts->read_rep > ts->debounce_rep) {
/* Got a good reading for this coordinate,
* go for the next one. */
+ ts->tc.ignore = 0;
+ ts->msg_idx++;
ts->read_cnt = 0;
ts->read_rep = 0;
- return ADS7846_FILTER_OK;
- } else {
+ m++;
+ } else
/* Read more values that are consistent. */
ts->read_cnt++;
- return ADS7846_FILTER_REPEAT;
- }
}
-}
-
-static int ads7846_no_filter(void *ads, int data_idx, int *val)
-{
- return ADS7846_FILTER_OK;
-}
-
-static void ads7846_rx_val(void *ads)
-{
- struct ads7846 *ts = ads;
- struct ads7846_packet *packet = ts->packet;
- struct spi_message *m;
- struct spi_transfer *t;
- int val;
- int action;
- int status;
-
- m = &ts->msg[ts->msg_idx];
- t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
-
- /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding;
- * built from two 8 bit values written msb-first.
- */
- val = be16_to_cpup((__be16 *)t->rx_buf) >> 3;
-
- action = ts->filter(ts->filter_data, ts->msg_idx, &val);
- switch (action) {
- case ADS7846_FILTER_REPEAT:
- break;
- case ADS7846_FILTER_IGNORE:
- packet->tc.ignore = 1;
- /* Last message will contain ads7846_rx() as the
- * completion function.
- */
- m = ts->last_msg;
- break;
- case ADS7846_FILTER_OK:
- *(u16 *)t->rx_buf = val;
- packet->tc.ignore = 0;
- m = &ts->msg[++ts->msg_idx];
- break;
- default:
- BUG();
- }
- ts->wait_for_sync();
status = spi_async(ts->spi, m);
if (status)
dev_err(&ts->spi->dev, "spi_async --> %d\n",
status);
}
-static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
+static void ads7846_timer(unsigned long handle)
{
- struct ads7846 *ts = container_of(handle, struct ads7846, timer);
- int status = 0;
+ struct ads7846 *ts = (void *)handle;
+ struct input_dev *input_dev = ts->input;
+ int status = 0;
- spin_lock(&ts->lock);
-
- if (unlikely(!get_pendown_state(ts) ||
- device_suspended(&ts->spi->dev))) {
- if (ts->pendown) {
- struct input_dev *input = ts->input;
-
- input_report_key(input, BTN_TOUCH, 0);
- input_report_abs(input, ABS_PRESSURE, 0);
- input_sync(input);
+ /* get sample */
+ ts->pendown = ts->get_pendown_state();
+ spin_lock_irq(&ts->lock);
+ if (ts->model == 7843) {
+ ts->pending = 0;
+ if (unlikely(!ts->pendown)) {
- ts->pendown = 0;
-#ifdef VERBOSE
- dev_dbg(&ts->spi->dev, "UP\n");
-#endif
- }
+ input_report_key(input_dev, BTN_TOUCH, 0);
+ input_report_abs(input_dev, ABS_PRESSURE, 0);
+ input_sync(input_dev);
- /* measurement cycle ended */
- if (!device_suspended(&ts->spi->dev)) {
- ts->irq_disabled = 0;
- enable_irq(ts->spi->irq);
+ if (!device_suspended(&ts->spi->dev)) {
+ ts->irq_disabled = 0;
+ enable_irq(ts->spi->irq);
+ }
+ } else {
+ /* pen is still down, continue with the measurement */
+ status = spi_async(ts->spi, &ts->msg[0]);
+ if (status)
+ dev_err(&ts->spi->dev, "spi_async --> %d\n", status);
}
- ts->pending = 0;
} else {
- /* pen is still down, continue with the measurement */
- ts->msg_idx = 0;
- ts->wait_for_sync();
- status = spi_async(ts->spi, &ts->msg[0]);
- if (status)
- dev_err(&ts->spi->dev, "spi_async --> %d\n", status);
+ if (unlikely(ts->msg_idx && !ts->pendown)) {
+ /* measurement cycle ended */
+ if (!device_suspended(&ts->spi->dev)) {
+ ts->irq_disabled = 0;
+ enable_irq(ts->spi->irq);
+ }
+ ts->pending = 0;
+ ts->msg_idx = 0;
+ } else {
+ /* pen is still down, continue with the measurement */
+ ts->msg_idx = 0;
+ status = spi_async(ts->spi, &ts->msg[0]);
+ if (status)
+ dev_err(&ts->spi->dev, "spi_async --> %d\n", status);
+ }
}
-
- spin_unlock(&ts->lock);
- return HRTIMER_NORESTART;
+ spin_unlock_irq(&ts->lock);
}
static irqreturn_t ads7846_irq(int irq, void *handle)
@@ -753,7 +687,8 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
- if (likely(get_pendown_state(ts))) {
+
+ if (likely(ts->get_pendown_state())) {
if (!ts->irq_disabled) {
/* The ARM do_simple_IRQ() dispatcher doesn't act
* like the other dispatchers: it will report IRQs
@@ -763,8 +698,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
ts->irq_disabled = 1;
disable_irq_nosync(ts->spi->irq);
ts->pending = 1;
- hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
- HRTIMER_MODE_REL);
+ mod_timer(&ts->timer, jiffies);
}
}
spin_unlock_irqrestore(&ts->lock, flags);
@@ -785,7 +719,7 @@ static void ads7846_disable(struct ads7846 *ts)
/* are we waiting for IRQ, or polling? */
if (!ts->pending) {
ts->irq_disabled = 1;
- disable_irq(ts->spi->irq);
+ disable_irq_nosync(ts->spi->irq);
} else {
/* the timer will run at least once more, and
* leave everything in a clean state, IRQ disabled
@@ -800,6 +734,7 @@ static void ads7846_disable(struct ads7846 *ts)
/* we know the chip's in lowpower mode since we always
* leave it that way after every request
*/
+
}
/* Must be called with ts->lock held */
@@ -819,7 +754,7 @@ static int ads7846_suspend(struct spi_device *spi, pm_message_t message)
spin_lock_irq(&ts->lock);
- ts->is_suspended = 1;
+ spi->dev.power.power_state = message;
ads7846_disable(ts);
spin_unlock_irq(&ts->lock);
@@ -834,7 +769,7 @@ static int ads7846_resume(struct spi_device *spi)
spin_lock_irq(&ts->lock);
- ts->is_suspended = 0;
+ spi->dev.power.power_state = PMSG_ON;
ads7846_enable(ts);
spin_unlock_irq(&ts->lock);
@@ -842,45 +777,13 @@ static int ads7846_resume(struct spi_device *spi)
return 0;
}
-static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
-{
- struct ads7846_platform_data *pdata = spi->dev.platform_data;
- int err;
-
- /* REVISIT when the irq can be triggered active-low, or if for some
- * reason the touchscreen isn't hooked up, we don't need to access
- * the pendown state.
- */
- if (!pdata->get_pendown_state && !gpio_is_valid(pdata->gpio_pendown)) {
- dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
- return -EINVAL;
- }
-
- if (pdata->get_pendown_state) {
- ts->get_pendown_state = pdata->get_pendown_state;
- return 0;
- }
-
- err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
- if (err) {
- dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
- pdata->gpio_pendown);
- return err;
- }
-
- ts->gpio_pendown = pdata->gpio_pendown;
- return 0;
-}
-
static int __devinit ads7846_probe(struct spi_device *spi)
{
struct ads7846 *ts;
- struct ads7846_packet *packet;
struct input_dev *input_dev;
struct ads7846_platform_data *pdata = spi->dev.platform_data;
struct spi_message *m;
struct spi_transfer *x;
- int vref;
int err;
if (!spi->irq) {
@@ -900,33 +803,46 @@ static int __devinit ads7846_probe(struct spi_device *spi)
return -EINVAL;
}
+ /* REVISIT when the irq can be triggered active-low, or if for some
+ * reason the touchscreen isn't hooked up, we don't need to access
+ * the pendown state.
+ */
+ if (pdata->get_pendown_state == NULL) {
+ dev_dbg(&spi->dev, "no get_pendown_state function?\n");
+ return -EINVAL;
+ }
+
/* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except
* that even if the hardware can do that, the SPI controller driver
* may not. So we stick to very-portable 8 bit words, both RX and TX.
*/
spi->bits_per_word = 8;
- spi->mode = SPI_MODE_0;
- err = spi_setup(spi);
- if (err < 0)
- return err;
ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
- packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
input_dev = input_allocate_device();
- if (!ts || !packet || !input_dev) {
+ if (!ts || !input_dev) {
err = -ENOMEM;
goto err_free_mem;
}
dev_set_drvdata(&spi->dev, ts);
- ts->packet = packet;
+ spi->dev.power.power_state = PMSG_ON;
+
ts->spi = spi;
ts->input = input_dev;
- ts->vref_mv = pdata->vref_mv;
- ts->swap_xy = pdata->swap_xy;
- hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ts->buflen = pdata->buflen ? : MAX_BUF_SAMPLE_LEN;
+ ts->buflen = ts->buflen & ~0x1; /* must be even */
+
+ if (ads7843_setup_buffers(&spi->dev)) {
+ dev_dbg(&spi->dev, "error allocating memory for sample buffers\n");
+ err = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ init_timer(&ts->timer);
+ ts->timer.data = (unsigned long) ts;
ts->timer.function = ads7846_timer;
spin_lock_init(&ts->lock);
@@ -935,40 +851,22 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
ts->pressure_max = pdata->pressure_max ? : ~0;
+ ts->skip_samples = pdata->skip_samples ? : 0;
+ ts->rotate = pdata->rotate ? : 0;
- if (pdata->filter != NULL) {
- if (pdata->filter_init != NULL) {
- err = pdata->filter_init(pdata, &ts->filter_data);
- if (err < 0)
- goto err_free_mem;
- }
- ts->filter = pdata->filter;
- ts->filter_cleanup = pdata->filter_cleanup;
- } else if (pdata->debounce_max) {
+ if (pdata->debounce_max) {
ts->debounce_max = pdata->debounce_max;
- if (ts->debounce_max < 2)
- ts->debounce_max = 2;
ts->debounce_tol = pdata->debounce_tol;
ts->debounce_rep = pdata->debounce_rep;
- ts->filter = ads7846_debounce;
- ts->filter_data = ts;
+ if (ts->debounce_rep > ts->debounce_max + 1)
+ ts->debounce_rep = ts->debounce_max - 1;
} else
- ts->filter = ads7846_no_filter;
-
- err = setup_pendown(spi, ts);
- if (err)
- goto err_cleanup_filter;
-
- if (pdata->penirq_recheck_delay_usecs)
- ts->penirq_recheck_delay_usecs =
- pdata->penirq_recheck_delay_usecs;
-
- ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
+ ts->debounce_tol = ~0;
+ ts->get_pendown_state = pdata->get_pendown_state;
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
- snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
- input_dev->name = ts->name;
+ input_dev->name = "ADS784x Touchscreen";
input_dev->phys = ts->phys;
input_dev->dev.parent = &spi->dev;
@@ -983,9 +881,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
pdata->y_max ? : MAX_12BIT,
0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE,
- pdata->pressure_min, pdata->pressure_max, 0, 0);
-
- vref = pdata->keep_vref_on;
+ pdata->pressure_min ? : 0,
+ pdata->pressure_max ? : 1, 0, 0);
/* set up the transfers to read touchscreen state; this assumes we
* use formula #2 for pressure, not #3.
@@ -995,209 +892,176 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init(m);
- /* y- still on; turn on only y+ (and ADC) */
- packet->read_y = READ_Y(vref);
- x->tx_buf = &packet->read_y;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
- x->rx_buf = &packet->tc.y;
- x->len = 2;
- spi_message_add_tail(x, m);
-
- /* the first sample after switching drivers can be low quality;
- * optionally discard it, using a second one after the signals
- * have had enough time to stabilize.
- */
- if (pdata->settle_delay_usecs) {
- x->delay_usecs = pdata->settle_delay_usecs;
-
- x++;
- x->tx_buf = &packet->read_y;
- x->len = 1;
+ if (ts->model == 7843) {
+ x->tx_buf = ts->txbuf;
+ x->rx_buf = ts->rxbuf;
+ x->len = ts->buflen * sizeof(u32) * 3; /* For every sample we take 3 samples and choose the better 2 */
spi_message_add_tail(x, m);
- x++;
- x->rx_buf = &packet->tc.y;
- x->len = 2;
- spi_message_add_tail(x, m);
- }
-
- m->complete = ads7846_rx_val;
- m->context = ts;
-
- m++;
- spi_message_init(m);
-
- /* turn y- off, x+ on, then leave in lowpower */
- x++;
- packet->read_x = READ_X(vref);
- x->tx_buf = &packet->read_x;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
- x->rx_buf = &packet->tc.x;
- x->len = 2;
- spi_message_add_tail(x, m);
-
- /* ... maybe discard first sample ... */
- if (pdata->settle_delay_usecs) {
- x->delay_usecs = pdata->settle_delay_usecs;
+ m->complete = ads7843_rx_average;
+ m->context = ts;
- x++;
- x->tx_buf = &packet->read_x;
+ ts->last_msg = m;
+ } else {
+ /* y- still on; turn on only y+ (and ADC) */
+ ts->read_y = READ_Y;
+ x->tx_buf = &ts->read_y;
x->len = 1;
spi_message_add_tail(x, m);
x++;
- x->rx_buf = &packet->tc.x;
+ x->rx_buf = &ts->tc.y;
x->len = 2;
spi_message_add_tail(x, m);
- }
- m->complete = ads7846_rx_val;
- m->context = ts;
+ m->complete = ads7846_debounce;
+ m->context = ts;
- /* turn y+ off, x- on; we'll use formula #2 */
- if (ts->model == 7846) {
m++;
spi_message_init(m);
+ /* turn y- off, x+ on, then leave in lowpower */
x++;
- packet->read_z1 = READ_Z1(vref);
- x->tx_buf = &packet->read_z1;
+ ts->read_x = READ_X;
+ x->tx_buf = &ts->read_x;
x->len = 1;
spi_message_add_tail(x, m);
x++;
- x->rx_buf = &packet->tc.z1;
+ x->rx_buf = &ts->tc.x;
x->len = 2;
spi_message_add_tail(x, m);
- /* ... maybe discard first sample ... */
- if (pdata->settle_delay_usecs) {
- x->delay_usecs = pdata->settle_delay_usecs;
+ m->complete = ads7846_debounce;
+ m->context = ts;
+
+ /* turn y+ off, x- on; we'll use formula #2 */
+ if (ts->model == 7846) {
+ m++;
+ spi_message_init(m);
x++;
- x->tx_buf = &packet->read_z1;
+ ts->read_z1 = READ_Z1;
+ x->tx_buf = &ts->read_z1;
x->len = 1;
spi_message_add_tail(x, m);
x++;
- x->rx_buf = &packet->tc.z1;
+ x->rx_buf = &ts->tc.z1;
x->len = 2;
spi_message_add_tail(x, m);
- }
-
- m->complete = ads7846_rx_val;
- m->context = ts;
-
- m++;
- spi_message_init(m);
- x++;
- packet->read_z2 = READ_Z2(vref);
- x->tx_buf = &packet->read_z2;
- x->len = 1;
- spi_message_add_tail(x, m);
-
- x++;
- x->rx_buf = &packet->tc.z2;
- x->len = 2;
- spi_message_add_tail(x, m);
+ m->complete = ads7846_debounce;
+ m->context = ts;
- /* ... maybe discard first sample ... */
- if (pdata->settle_delay_usecs) {
- x->delay_usecs = pdata->settle_delay_usecs;
+ m++;
+ spi_message_init(m);
x++;
- x->tx_buf = &packet->read_z2;
+ ts->read_z2 = READ_Z2;
+ x->tx_buf = &ts->read_z2;
x->len = 1;
spi_message_add_tail(x, m);
x++;
- x->rx_buf = &packet->tc.z2;
+ x->rx_buf = &ts->tc.z2;
x->len = 2;
spi_message_add_tail(x, m);
- }
- m->complete = ads7846_rx_val;
- m->context = ts;
- }
+ m->complete = ads7846_debounce;
+ m->context = ts;
+ }
- /* power down */
- m++;
- spi_message_init(m);
+ /* power down */
+ m++;
+ spi_message_init(m);
- x++;
- packet->pwrdown = PWRDOWN;
- x->tx_buf = &packet->pwrdown;
- x->len = 1;
- spi_message_add_tail(x, m);
+ x++;
+ ts->pwrdown = PWRDOWN;
+ x->tx_buf = &ts->pwrdown;
+ x->len = 1;
+ spi_message_add_tail(x, m);
- x++;
- x->rx_buf = &packet->dummy;
- x->len = 2;
- CS_CHANGE(*x);
- spi_message_add_tail(x, m);
+ x++;
+ x->rx_buf = &ts->dummy;
+ x->len = 2;
+ CS_CHANGE(*x);
+ spi_message_add_tail(x, m);
- m->complete = ads7846_rx;
- m->context = ts;
+ m->complete = ads7846_rx;
+ m->context = ts;
- ts->last_msg = m;
+ ts->last_msg = m;
+ }
if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
spi->dev.driver->name, ts)) {
- dev_info(&spi->dev,
- "trying pin change workaround on irq %d\n", spi->irq);
- err = request_irq(spi->irq, ads7846_irq,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- spi->dev.driver->name, ts);
- if (err) {
- dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
- goto err_free_gpio;
- }
+ dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
+ err = -EBUSY;
+ goto err_free_buf;
}
- err = ads784x_hwmon_register(spi, ts);
- if (err)
- goto err_free_irq;
-
dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
- /* take a first sample, leaving nPENIRQ active and vREF off; avoid
+ /* take a first sample, leaving nPENIRQ active; avoid
* the touchscreen, in case it's not connected.
*/
- (void) ads7846_read12_ser(&spi->dev,
- READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+ if (ts->model != 7843) {
+ /* take a first sample, leaving nPENIRQ active; avoid
+ * the touchscreen, in case it's not connected.
+ */
+ (void) ads7846_read12_ser(&spi->dev,
+ READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+ }
- err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
- if (err)
- goto err_remove_hwmon;
+ /* ads7843/7845 don't have temperature sensors, and
+ * use the other sensors a bit differently too
+ */
+ if (ts->model == 7846) {
+ device_create_file(&spi->dev, &dev_attr_temp0);
+ device_create_file(&spi->dev, &dev_attr_temp1);
+ }
+
+ if (ts->model != 7845 && ts->model != 7843)
+ device_create_file(&spi->dev, &dev_attr_vbatt);
+
+ if (ts->model != 7843) {
+ device_create_file(&spi->dev, &dev_attr_vaux);
+ }
+
+ device_create_file(&spi->dev, &dev_attr_pen_down);
+ device_create_file(&spi->dev, &dev_attr_disable);
err = input_register_device(input_dev);
if (err)
- goto err_remove_attr_group;
+ goto err_remove_attr;
return 0;
- err_remove_attr_group:
- sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
- err_remove_hwmon:
- ads784x_hwmon_unregister(spi, ts);
- err_free_irq:
+ err_remove_attr:
+ device_remove_file(&spi->dev, &dev_attr_disable);
+ device_remove_file(&spi->dev, &dev_attr_pen_down);
+ if (ts->model == 7846) {
+ device_remove_file(&spi->dev, &dev_attr_temp1);
+ device_remove_file(&spi->dev, &dev_attr_temp0);
+ }
+
+ if (ts->model != 7845 && ts->model != 7843)
+ device_remove_file(&spi->dev, &dev_attr_vbatt);
+
+ if (ts->model != 7843) {
+ device_remove_file(&spi->dev, &dev_attr_vaux);
+ }
+
free_irq(spi->irq, ts);
- err_free_gpio:
- if (ts->gpio_pendown != -1)
- gpio_free(ts->gpio_pendown);
- err_cleanup_filter:
- if (ts->filter_cleanup)
- ts->filter_cleanup(ts->filter_data);
+
+ err_free_buf:
+ if (ts->txbuf)
+ kfree(ts->txbuf);
+ if (ts->rxbuf)
+ kfree(ts->rxbuf);
err_free_mem:
input_free_device(input_dev);
- kfree(packet);
kfree(ts);
return err;
}
@@ -1206,24 +1070,33 @@ static int __devexit ads7846_remove(struct spi_device *spi)
{
struct ads7846 *ts = dev_get_drvdata(&spi->dev);
- ads784x_hwmon_unregister(spi, ts);
input_unregister_device(ts->input);
ads7846_suspend(spi, PMSG_SUSPEND);
- sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
+ if (ts->txbuf)
+ kfree(ts->txbuf);
+ if (ts->rxbuf)
+ kfree(ts->rxbuf);
- free_irq(ts->spi->irq, ts);
- /* suspend left the IRQ disabled */
- enable_irq(ts->spi->irq);
+ device_remove_file(&spi->dev, &dev_attr_disable);
+ device_remove_file(&spi->dev, &dev_attr_pen_down);
+ if (ts->model == 7846) {
+ device_remove_file(&spi->dev, &dev_attr_temp1);
+ device_remove_file(&spi->dev, &dev_attr_temp0);
+ }
+
+ if (ts->model != 7845 && ts->model != 7843)
+ device_remove_file(&spi->dev, &dev_attr_vbatt);
- if (ts->gpio_pendown != -1)
- gpio_free(ts->gpio_pendown);
+ if (ts->model != 7843) {
+ device_remove_file(&spi->dev, &dev_attr_vaux);
+ }
- if (ts->filter_cleanup)
- ts->filter_cleanup(ts->filter_data);
+ free_irq(ts->spi->irq, ts);
+ /* suspend left the IRQ disabled */
+ disable_irq_nosync(ts->spi->irq);
- kfree(ts->packet);
kfree(ts);
dev_dbg(&spi->dev, "unregistered touchscreen\n");
diff --git a/drivers/input/touchscreen/mxc_ts.c b/drivers/input/touchscreen/mxc_ts.c
index 610f31e65778..6cce76f1494f 100644
--- a/drivers/input/touchscreen/mxc_ts.c
+++ b/drivers/input/touchscreen/mxc_ts.c
@@ -43,6 +43,9 @@
#include <linux/pmic_external.h>
#include <linux/pmic_adc.h>
#include <linux/kthread.h>
+#ifdef CONFIG_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
#define MXC_TS_NAME "mxc_ts"
@@ -60,6 +63,30 @@ static struct task_struct *tstask;
static int calibration[7];
module_param_array(calibration, int, NULL, S_IRUGO | S_IWUSR);
+#ifdef CONFIG_EARLYSUSPEND
+
+static wait_queue_head_t ts_wait;
+static int ts_suspend;
+
+static void stop_ts_early_suspend(struct early_suspend *h)
+{
+ ts_suspend = 1;
+}
+
+static void start_ts_late_resume(struct early_suspend *h)
+{
+ ts_suspend = 0;
+ wake_up_interruptible(&ts_wait);
+}
+
+static struct early_suspend stop_ts_early_suspend_desc = {
+ .level = EARLY_SUSPEND_LEVEL_STOP_DRAWING,
+ .suspend = stop_ts_early_suspend,
+ .resume = start_ts_late_resume,
+};
+
+#endif
+
static int ts_thread(void *arg)
{
t_touch_screen ts_sample;
@@ -69,6 +96,9 @@ static int ts_thread(void *arg)
int x, y;
static int last_x = -1, last_y = -1, last_press = -1;
+#ifdef CONFIG_EARLYSUSPEND
+ wait_event_interruptible(ts_wait, !ts_suspend);
+#endif
memset(&ts_sample, 0, sizeof(t_touch_screen));
/* After 2 consecutive samples with the pen up, enable irq waiting */
@@ -76,14 +106,13 @@ static int ts_thread(void *arg)
msleep(20);
continue;
}
- if (!(ts_sample.contact_resistance || wait))
- {
+ if (!(ts_sample.contact_resistance || wait)) {
msleep(20);
continue;
}
if (ts_sample.x_position == 0 && ts_sample.y_position == 0 &&
- ts_sample.contact_resistance == 0) {
+ ts_sample.contact_resistance == 0) {
x = last_x;
y = last_y;
} else if (calibration[6] == 0) {
@@ -91,14 +120,14 @@ static int ts_thread(void *arg)
y = ts_sample.y_position;
} else {
x = calibration[0] * (int)ts_sample.x_position +
- calibration[1] * (int)ts_sample.y_position +
- calibration[2];
+ calibration[1] * (int)ts_sample.y_position +
+ calibration[2];
x /= calibration[6];
if (x < 0)
x = 0;
y = calibration[3] * (int)ts_sample.x_position +
- calibration[4] * (int)ts_sample.y_position +
- calibration[5];
+ calibration[4] * (int)ts_sample.y_position +
+ calibration[5];
y /= calibration[6];
if (y < 0)
y = 0;
@@ -127,7 +156,7 @@ static int ts_thread(void *arg)
/* report the BTN_TOUCH */
if (ts_sample.contact_resistance != last_press)
input_event(mxc_inputdev, EV_KEY,
- BTN_TOUCH, ts_sample.contact_resistance);
+ BTN_TOUCH, ts_sample.contact_resistance);
input_sync(mxc_inputdev);
last_press = ts_sample.contact_resistance;
@@ -148,8 +177,7 @@ static int __init mxc_ts_init(void)
mxc_inputdev = input_allocate_device();
if (!mxc_inputdev) {
- printk(KERN_ERR
- "mxc_ts_init: not enough memory\n");
+ printk(KERN_ERR "mxc_ts_init: not enough memory\n");
return -ENOMEM;
}
@@ -166,11 +194,14 @@ static int __init mxc_ts_init(void)
tstask = kthread_run(ts_thread, NULL, "mxc_ts");
if (IS_ERR(tstask)) {
- printk(KERN_ERR
- "mxc_ts_init: failed to create kthread");
+ printk(KERN_ERR "mxc_ts_init: failed to create kthread");
tstask = NULL;
return -1;
}
+#ifdef CONFIG_EARLYSUSPEND
+ init_waitqueue_head(&ts_wait);
+ register_early_suspend(&stop_ts_early_suspend_desc);
+#endif
printk("mxc input touchscreen loaded\n");
return 0;
}
@@ -186,6 +217,9 @@ static void __exit mxc_ts_exit(void)
input_free_device(mxc_inputdev);
mxc_inputdev = NULL;
}
+#ifdef CONFIG_EARLYSUSPEND
+ unregister_early_suspend(&stop_ts_early_suspend_desc);
+#endif
}
late_initcall(mxc_ts_init);
diff --git a/drivers/leds/leds-mxs-pwm.c b/drivers/leds/leds-mxs-pwm.c
index c76821770446..a546900a44d0 100644
--- a/drivers/leds/leds-mxs-pwm.c
+++ b/drivers/leds/leds-mxs-pwm.c
@@ -165,10 +165,35 @@ static int __devexit mxs_pwm_led_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int mxs_led_suspend(struct platform_device *dev, pm_message_t state)
+{
+ int i;
+
+ for (i = 0; i < leds.led_num; i++)
+ led_classdev_suspend(&leds.leds[i].dev);
+ return 0;
+}
+
+static int mxs_led_resume(struct platform_device *dev)
+{
+ int i;
+
+ for (i = 0; i < leds.led_num; i++)
+ led_classdev_resume(&leds.leds[i].dev);
+ return 0;
+}
+#else
+#define mxs_led_suspend NULL
+#define mxs_led_resume NULL
+#endif
+
static struct platform_driver mxs_pwm_led_driver = {
.probe = mxs_pwm_led_probe,
.remove = __devexit_p(mxs_pwm_led_remove),
+ .suspend = mxs_led_suspend,
+ .resume = mxs_led_resume,
.driver = {
.name = "mxs-leds",
},
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index c64c8d201262..e7185d1cf281 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -592,6 +592,17 @@ config VIDEO_MXS_PXP
To compile this driver as a module, choose M here: the
module will be called pxp.
+config VIDEO_MXC_PXP_V4L2
+ tristate "MXC PxP V4L2 driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_MX5
+ select VIDEOBUF_DMA_CONTIG
+ ---help---
+ This is a video4linux driver for the Freescale PxP
+ (Pixel Pipeline). This module supports output overlay of
+ the MXC framebuffer on a video stream.
+
+ To compile this driver as a module, choose M here.
+
config VIDEO_MXC_OPL
tristate
depends on VIDEO_DEV && ARCH_MXC
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 49cb18802024..a4de2a151253 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -94,6 +94,7 @@ obj-$(CONFIG_VIDEO_MXC_CSI_CAMERA) += mxc/capture/
obj-$(CONFIG_VIDEO_MXC_IPU_OUTPUT) += mxc/output/
obj-$(CONFIG_VIDEO_MXC_IPUV1_WVGA_OUTPUT) += mxc/output/
obj-$(CONFIG_VIDEO_MXC_EMMA_OUTPUT) += mxc/output/
+obj-$(CONFIG_VIDEO_MXC_PXP_V4L2) += mxc/output/
obj-$(CONFIG_VIDEO_MXC_OPL) += mxc/opl/
obj-$(CONFIG_VIDEO_PXP) += pxp.o
obj-$(CONFIG_VIDEO_MXS_PXP) += mxs_pxp.o
diff --git a/drivers/media/video/mxc/capture/Kconfig b/drivers/media/video/mxc/capture/Kconfig
index adab0a886f36..276dfa424feb 100644
--- a/drivers/media/video/mxc/capture/Kconfig
+++ b/drivers/media/video/mxc/capture/Kconfig
@@ -58,6 +58,22 @@ config MXC_CAMERA_MICRON111
---help---
If you plan to use the mt9v111 Camera with your MXC system, say Y here.
+config MXC_CAMERA_MICRON111_1
+ tristate "Micron mt9v111 camera 1 support"
+ select I2C_MXC
+ depends on ! VIDEO_MXC_EMMA_CAMERA
+ depends on MXC_CAMERA_MICRON111
+ ---help---
+ If you plan to use the mt9v111 Camera 1 with your MXC system, say Y here.
+
+config MXC_CAMERA_MICRON111_2
+ tristate "Micron mt9v111 camera 2 support"
+ select I2C_MXC
+ depends on ! VIDEO_MXC_EMMA_CAMERA
+ depends on MXC_CAMERA_MICRON111
+ ---help---
+ If you plan to use the mt9v111 Camera 2 with your MXC system, say Y here.
+
config MXC_CAMERA_OV2640
tristate "OmniVision ov2640 camera support"
depends on !VIDEO_MXC_EMMA_CAMERA
@@ -72,7 +88,7 @@ config MXC_CAMERA_OV3640
config MXC_TVIN_ADV7180
tristate "Analog Device adv7180 TV Decoder Input support"
- depends on MACH_MX35_3DS
+ depends on (MACH_MX35_3DS || MACH_MX51_3DS)
---help---
If you plan to use the adv7180 video decoder with your MXC system, say Y here.
diff --git a/drivers/media/video/mxc/capture/Makefile b/drivers/media/video/mxc/capture/Makefile
index 112923c8fc8f..03ff094171bf 100644
--- a/drivers/media/video/mxc/capture/Makefile
+++ b/drivers/media/video/mxc/capture/Makefile
@@ -35,5 +35,5 @@ obj-$(CONFIG_MXC_CAMERA_OV2640) += ov2640_camera.o
ov3640_camera-objs := ov3640.o sensor_clock.o
obj-$(CONFIG_MXC_CAMERA_OV3640) += ov3640_camera.o
-adv7180_tvin-objs := adv7180.o sensor_clock.o
+adv7180_tvin-objs := adv7180.o
obj-$(CONFIG_MXC_TVIN_ADV7180) += adv7180_tvin.o
diff --git a/drivers/media/video/mxc/capture/adv7180.c b/drivers/media/video/mxc/capture/adv7180.c
index 1edee763bebc..527a0d1ad9fa 100644
--- a/drivers/media/video/mxc/capture/adv7180.c
+++ b/drivers/media/video/mxc/capture/adv7180.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -39,6 +39,7 @@ static struct regulator *dvddio_regulator;
static struct regulator *dvdd_regulator;
static struct regulator *avdd_regulator;
static struct regulator *pvdd_regulator;
+static struct mxc_tvin_platform_data *tvin_plat;
extern void gpio_sensor_active(void);
extern void gpio_sensor_inactive(void);
@@ -118,26 +119,26 @@ static video_fmt_t video_fmts[] = {
{ /*! NTSC */
.v4l2_id = V4L2_STD_NTSC,
.name = "NTSC",
- .raw_width = 720 - 1, /* SENS_FRM_WIDTH */
- .raw_height = 288 - 1, /* SENS_FRM_HEIGHT */
+ .raw_width = 720, /* SENS_FRM_WIDTH */
+ .raw_height = 525, /* SENS_FRM_HEIGHT */
.active_width = 720, /* ACT_FRM_WIDTH plus 1 */
- .active_height = (480 / 2), /* ACT_FRM_WIDTH plus 1 */
+ .active_height = 480, /* ACT_FRM_WIDTH plus 1 */
},
{ /*! (B, G, H, I, N) PAL */
.v4l2_id = V4L2_STD_PAL,
.name = "PAL",
- .raw_width = 720 - 1,
- .raw_height = (576 / 2) + 24 * 2 - 1,
+ .raw_width = 720,
+ .raw_height = 625,
.active_width = 720,
- .active_height = (576 / 2),
+ .active_height = 576,
},
{ /*! Unlocked standard */
.v4l2_id = V4L2_STD_ALL,
.name = "Autodetect",
- .raw_width = 720 - 1,
- .raw_height = (576 / 2) + 24 * 2 - 1,
+ .raw_width = 720,
+ .raw_height = 625,
.active_width = 720,
- .active_height = (576 / 2),
+ .active_height = 576,
},
};
@@ -246,6 +247,10 @@ static void adv7180_get_std(v4l2_std_id *std)
dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180_get_std\n");
+ /* Make sure power on */
+ if (tvin_plat->pwdn)
+ tvin_plat->pwdn(0);
+
/* Read the AD_RESULT to get the detect output video standard */
tmp = adv7180_read(ADV7180_STATUS_1) & 0x70;
@@ -335,6 +340,11 @@ static int ioctl_s_power(struct v4l2_int_device *s, int on)
if (on && !sensor->on) {
gpio_sensor_active();
+
+ /* Make sure pwoer on */
+ if (tvin_plat->pwdn)
+ tvin_plat->pwdn(0);
+
if (adv7180_write_reg(ADV7180_PWR_MNG, 0) != 0)
return -EIO;
} else if (!on && sensor->on) {
@@ -500,6 +510,10 @@ static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_g_ctrl\n");
+ /* Make sure power on */
+ if (tvin_plat->pwdn)
+ tvin_plat->pwdn(0);
+
switch (vc->id) {
case V4L2_CID_BRIGHTNESS:
dev_dbg(&adv7180_data.i2c_client->dev,
@@ -593,6 +607,10 @@ static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180:ioctl_s_ctrl\n");
+ /* Make sure power on */
+ if (tvin_plat->pwdn)
+ tvin_plat->pwdn(0);
+
switch (vc->id) {
case V4L2_CID_BRIGHTNESS:
dev_dbg(&adv7180_data.i2c_client->dev,
@@ -803,13 +821,13 @@ static int adv7180_probe(struct i2c_client *client,
{
int rev_id;
int ret = 0;
- struct mxc_tvin_platform_data *plat_data = client->dev.platform_data;
+ tvin_plat = client->dev.platform_data;
dev_dbg(&adv7180_data.i2c_client->dev, "In adv7180_probe\n");
- if (plat_data->dvddio_reg) {
+ if (tvin_plat->dvddio_reg) {
dvddio_regulator =
- regulator_get(&client->dev, plat_data->dvddio_reg);
+ regulator_get(&client->dev, tvin_plat->dvddio_reg);
if (!IS_ERR_VALUE((unsigned long)dvddio_regulator)) {
regulator_set_voltage(dvddio_regulator, 3300000, 3300000);
if (regulator_enable(dvddio_regulator) != 0)
@@ -817,9 +835,9 @@ static int adv7180_probe(struct i2c_client *client,
}
}
- if (plat_data->dvdd_reg) {
+ if (tvin_plat->dvdd_reg) {
dvdd_regulator =
- regulator_get(&client->dev, plat_data->dvdd_reg);
+ regulator_get(&client->dev, tvin_plat->dvdd_reg);
if (!IS_ERR_VALUE((unsigned long)dvdd_regulator)) {
regulator_set_voltage(dvdd_regulator, 1800000, 1800000);
if (regulator_enable(dvdd_regulator) != 0)
@@ -827,9 +845,9 @@ static int adv7180_probe(struct i2c_client *client,
}
}
- if (plat_data->avdd_reg) {
+ if (tvin_plat->avdd_reg) {
avdd_regulator =
- regulator_get(&client->dev, plat_data->avdd_reg);
+ regulator_get(&client->dev, tvin_plat->avdd_reg);
if (!IS_ERR_VALUE((unsigned long)avdd_regulator)) {
regulator_set_voltage(avdd_regulator, 1800000, 1800000);
if (regulator_enable(avdd_regulator) != 0)
@@ -837,9 +855,9 @@ static int adv7180_probe(struct i2c_client *client,
}
}
- if (plat_data->pvdd_reg) {
+ if (tvin_plat->pvdd_reg) {
pvdd_regulator =
- regulator_get(&client->dev, plat_data->pvdd_reg);
+ regulator_get(&client->dev, tvin_plat->pvdd_reg);
if (!IS_ERR_VALUE((unsigned long)pvdd_regulator)) {
regulator_set_voltage(pvdd_regulator, 1800000, 1800000);
if (regulator_enable(pvdd_regulator) != 0)
@@ -847,11 +865,12 @@ static int adv7180_probe(struct i2c_client *client,
}
}
- if (plat_data->reset)
- plat_data->reset();
- if (plat_data->pwdn)
- plat_data->pwdn(1);
+ if (tvin_plat->reset)
+ tvin_plat->reset();
+
+ if (tvin_plat->pwdn)
+ tvin_plat->pwdn(0);
msleep(1);
@@ -913,7 +932,7 @@ static int adv7180_detach(struct i2c_client *client)
__func__, IF_NAME, client->addr << 1, client->adapter->name);
if (plat_data->pwdn)
- plat_data->pwdn(0);
+ plat_data->pwdn(1);
if (dvddio_regulator) {
regulator_disable(dvddio_regulator);
diff --git a/drivers/media/video/mxc/capture/csi_v4l2_capture.c b/drivers/media/video/mxc/capture/csi_v4l2_capture.c
index 9bddc3692996..cf224e0673f0 100644
--- a/drivers/media/video/mxc/capture/csi_v4l2_capture.c
+++ b/drivers/media/video/mxc/capture/csi_v4l2_capture.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -789,15 +789,15 @@ static ssize_t csi_v4l_read(struct file *file, char *buf, size_t count,
(cam->v2f.fmt.
pix.sizeimage),
&cam->
- still_buf,
+ still_buf[0],
GFP_DMA | GFP_KERNEL);
if (cam->still_buf_vaddr == NULL) {
pr_err("alloc dma memory failed\n");
return -ENOMEM;
}
cam->still_counter = 0;
- __raw_writel(cam->still_buf, CSI_CSIDMASA_FB2);
- __raw_writel(cam->still_buf, CSI_CSIDMASA_FB1);
+ __raw_writel(cam->still_buf[0], CSI_CSIDMASA_FB2);
+ __raw_writel(cam->still_buf[0], CSI_CSIDMASA_FB1);
__raw_writel(__raw_readl(CSI_CSICR3) | BIT_DMA_REFLASH_RFF,
CSI_CSICR3);
__raw_writel(__raw_readl(CSI_CSISR), CSI_CSISR);
@@ -813,8 +813,8 @@ static ssize_t csi_v4l_read(struct file *file, char *buf, size_t count,
if (cam->still_buf_vaddr != NULL) {
dma_free_coherent(0, PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
- cam->still_buf_vaddr, cam->still_buf);
- cam->still_buf = 0;
+ cam->still_buf_vaddr, cam->still_buf[0]);
+ cam->still_buf[0] = 0;
cam->still_buf_vaddr = NULL;
}
diff --git a/drivers/media/video/mxc/capture/emma_v4l2_capture.c b/drivers/media/video/mxc/capture/emma_v4l2_capture.c
index 9cb08b26f1cd..170807716ec6 100644
--- a/drivers/media/video/mxc/capture/emma_v4l2_capture.c
+++ b/drivers/media/video/mxc/capture/emma_v4l2_capture.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -858,7 +858,7 @@ static void mxc_csi_dma_chaining(void *data)
/* Config DMA */
memset(&dma_request, 0, sizeof(mxc_dma_requestbuf_t));
- dma_request.dst_addr = cam->still_buf
+ dma_request.dst_addr = cam->still_buf[0]
+ (chained % max_dma) * CSI_DMA_LENGTH;
dma_request.src_addr = (dma_addr_t) CSI_CSIRXFIFO_PHYADDR;
dma_request.num_of_bytes = count;
@@ -1040,7 +1040,7 @@ mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t *ppos)
cam->still_buf_vaddr = dma_alloc_coherent(0,
PAGE_ALIGN(CSI_MEM_SIZE),
- &cam->still_buf,
+ &cam->still_buf[0],
GFP_DMA | GFP_KERNEL);
if (!cam->still_buf_vaddr) {
@@ -1120,8 +1120,8 @@ mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t *ppos)
exit1:
dma_free_coherent(0, PAGE_ALIGN(CSI_MEM_SIZE),
- cam->still_buf_vaddr, cam->still_buf);
- cam->still_buf = 0;
+ cam->still_buf_vaddr, cam->still_buf[0]);
+ cam->still_buf[0] = 0;
exit0:
up(&cam->busy_lock);
@@ -1160,7 +1160,8 @@ mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t *ppos)
v_address = dma_alloc_coherent(0,
PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
- &cam->still_buf, GFP_DMA | GFP_KERNEL);
+ &cam->still_buf[0],
+ GFP_DMA | GFP_KERNEL);
if (!v_address) {
pr_info("mxc_v4l_read failed at allocate still_buf\n");
@@ -1194,8 +1195,8 @@ mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t *ppos)
exit1:
dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address,
- cam->still_buf);
- cam->still_buf = 0;
+ cam->still_buf[0]);
+ cam->still_buf[0] = 0;
exit0:
up(&cam->busy_lock);
diff --git a/drivers/media/video/mxc/capture/ipu_csi_enc.c b/drivers/media/video/mxc/capture/ipu_csi_enc.c
index fd3f0c132c14..0b87282551ff 100644
--- a/drivers/media/video/mxc/capture/ipu_csi_enc.c
+++ b/drivers/media/video/mxc/capture/ipu_csi_enc.c
@@ -25,6 +25,7 @@
#include "ipu_prp_sw.h"
#ifdef CAMERA_DBG
+ extern void ipu_dump_registers(void);
#define CAMERA_TRACE(x) (printk)x
#else
#define CAMERA_TRACE(x)
@@ -66,6 +67,7 @@ static int csi_enc_setup(cam_data *cam)
u32 pixel_fmt;
int err = 0;
dma_addr_t dummy = cam->dummy_frame.buffer.m.offset;
+ ipu_channel_t channel;
CAMERA_TRACE("In csi_enc_setup\n");
if (!cam) {
@@ -101,13 +103,18 @@ static int csi_enc_setup(cam_data *cam)
ipu_csi_enable_mclk_if(CSI_MCLK_ENC, cam->csi, true, true);
- err = ipu_init_channel(CSI_MEM, &params);
+ if (cam->csi == 0)
+ channel = CSI_MEM0;
+ else
+ channel = CSI_MEM1;
+
+ err = ipu_init_channel(channel, &params);
if (err != 0) {
printk(KERN_ERR "ipu_init_channel %d\n", err);
return err;
}
- err = ipu_init_channel_buffer(CSI_MEM, IPU_OUTPUT_BUFFER,
+ err = ipu_init_channel_buffer(channel, IPU_OUTPUT_BUFFER,
pixel_fmt, cam->v2f.fmt.pix.width,
cam->v2f.fmt.pix.height,
cam->v2f.fmt.pix.width, IPU_ROTATE_NONE,
@@ -115,12 +122,12 @@ static int csi_enc_setup(cam_data *cam)
cam->offset.u_offset,
cam->offset.v_offset);
if (err != 0) {
- printk(KERN_ERR "CSI_MEM output buffer\n");
+ printk(KERN_ERR "CSI_MEM%d output buffer\n",cam->csi);
return err;
}
- err = ipu_enable_channel(CSI_MEM);
+ err = ipu_enable_channel(channel);
if (err < 0) {
- printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
+ printk(KERN_ERR "ipu_enable_channel CSI_MEM%d\n",cam->csi);
return err;
}
@@ -135,24 +142,34 @@ static int csi_enc_setup(cam_data *cam)
*
* @return status
*/
-static int csi_enc_eba_update(dma_addr_t eba, int *buffer_num)
+static int csi_enc_eba_update(int csi, dma_addr_t eba, int *buffer_num)
{
int err = 0;
+ ipu_channel_t channel;
+
+ if (csi == 0)
+ channel = CSI_MEM0;
+ else
+ channel = CSI_MEM1;
- pr_debug("eba %x\n", eba);
- err = ipu_update_channel_buffer(CSI_MEM, IPU_OUTPUT_BUFFER,
+ err = ipu_update_channel_buffer(channel, IPU_OUTPUT_BUFFER,
*buffer_num, eba);
+
if (err != 0) {
- ipu_clear_buffer_ready(CSI_MEM, IPU_OUTPUT_BUFFER,
+ ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER,
*buffer_num);
printk(KERN_ERR "err %d buffer_num %d\n", err, *buffer_num);
return err;
}
- ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num);
+ ipu_select_buffer(channel, IPU_OUTPUT_BUFFER, *buffer_num);
*buffer_num = (*buffer_num == 0) ? 1 : 0;
+#ifdef CAMERA_DBG
+ ipu_dump_registers ();
+#endif
+
return 0;
}
@@ -166,6 +183,7 @@ static int csi_enc_enabling_tasks(void *private)
{
cam_data *cam = (cam_data *) private;
int err = 0;
+ int ipu_irq_csi_out_eof;
CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n");
cam->dummy_frame.vaddress = dma_alloc_coherent(0,
@@ -182,11 +200,16 @@ static int csi_enc_enabling_tasks(void *private)
PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress;
- ipu_clear_irq(IPU_IRQ_CSI0_OUT_EOF);
- err = ipu_request_irq(IPU_IRQ_CSI0_OUT_EOF,
- csi_enc_callback, 0, "Mxc Camera", cam);
+ if (cam->csi == 0)
+ ipu_irq_csi_out_eof = IPU_IRQ_CSI0_OUT_EOF;
+ else
+ ipu_irq_csi_out_eof = IPU_IRQ_CSI1_OUT_EOF;
+ ipu_clear_irq(ipu_irq_csi_out_eof);
+ err = ipu_request_irq(ipu_irq_csi_out_eof,
+ csi_enc_callback, 0, "Mxc Camera", cam);
+
if (err != 0) {
- printk(KERN_ERR "Error registering rot irq\n");
+ printk(KERN_ERR "Error registering eot irq for csi %d\n",cam->csi);
return err;
}
@@ -209,12 +232,24 @@ static int csi_enc_disabling_tasks(void *private)
{
cam_data *cam = (cam_data *) private;
int err = 0;
+ ipu_channel_t channel;
+ int ipu_irq_csi_out_eof;
- ipu_free_irq(IPU_IRQ_CSI0_OUT_EOF, cam);
+ if (cam->csi == 0)
+ {
+ channel = CSI_MEM0;
+ ipu_irq_csi_out_eof = IPU_IRQ_CSI0_OUT_EOF;
+ }
+ else
+ {
+ channel = CSI_MEM1;
+ ipu_irq_csi_out_eof = IPU_IRQ_CSI1_OUT_EOF;
+ }
- err = ipu_disable_channel(CSI_MEM, true);
+ ipu_free_irq(ipu_irq_csi_out_eof, cam);
+ err = ipu_disable_channel(channel, true);
- ipu_uninit_channel(CSI_MEM);
+ ipu_uninit_channel(channel);
if (cam->dummy_frame.vaddress != 0) {
dma_free_coherent(0, cam->dummy_frame.buffer.length,
diff --git a/drivers/media/video/mxc/capture/ipu_prp_enc.c b/drivers/media/video/mxc/capture/ipu_prp_enc.c
index 4b5426cb887d..0df8050ad7de 100644
--- a/drivers/media/video/mxc/capture/ipu_prp_enc.c
+++ b/drivers/media/video/mxc/capture/ipu_prp_enc.c
@@ -19,12 +19,14 @@
* @ingroup IPU
*/
+#include <linux/types.h>
#include <linux/dma-mapping.h>
#include <linux/ipu.h>
#include "mxc_v4l2_capture.h"
#include "ipu_prp_sw.h"
#ifdef CAMERA_DBG
+ extern void ipu_dump_registers(void);
#define CAMERA_TRACE(x) (printk)x
#else
#define CAMERA_TRACE(x)
@@ -266,11 +268,10 @@ static int prp_enc_setup(cam_data * cam)
*
* @return status
*/
-static int prp_enc_eba_update(dma_addr_t eba, int *buffer_num)
+static int prp_enc_eba_update(int csi, dma_addr_t eba, int *buffer_num)
{
int err = 0;
- pr_debug("eba %x\n", eba);
if (grotation >= IPU_ROTATE_90_RIGHT) {
err = ipu_update_channel_buffer(MEM_ROT_ENC_MEM,
IPU_OUTPUT_BUFFER, *buffer_num,
@@ -294,6 +295,11 @@ static int prp_enc_eba_update(dma_addr_t eba, int *buffer_num)
}
*buffer_num = (*buffer_num == 0) ? 1 : 0;
+
+#ifdef CAMERA_DBG
+ ipu_dump_registers ();
+#endif
+
return 0;
}
@@ -350,7 +356,6 @@ static int prp_enc_disabling_tasks(void *private)
if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
ipu_unlink_channels(CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM);
}
-
err = ipu_disable_channel(CSI_PRP_ENC_MEM, true);
if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
err |= ipu_disable_channel(MEM_ROT_ENC_MEM, true);
diff --git a/drivers/media/video/mxc/capture/ipu_prp_vf_sdc_bg.c b/drivers/media/video/mxc/capture/ipu_prp_vf_sdc_bg.c
index 7f0984c42950..9f8078d558b0 100644
--- a/drivers/media/video/mxc/capture/ipu_prp_vf_sdc_bg.c
+++ b/drivers/media/video/mxc/capture/ipu_prp_vf_sdc_bg.c
@@ -182,6 +182,7 @@ static int prpvf_start(void *private)
printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n");
goto out_3;
}
+
err = ipu_init_channel(MEM_ROT_VF_MEM, NULL);
if (err != 0) {
printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n");
@@ -200,6 +201,7 @@ static int prpvf_start(void *private)
}
if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
+
err = ipu_init_channel_buffer(MEM_ROT_VF_MEM, IPU_OUTPUT_BUFFER,
format,
vf.csi_prp_vf_mem.out_height,
diff --git a/drivers/media/video/mxc/capture/ipu_still.c b/drivers/media/video/mxc/capture/ipu_still.c
index 348bf2b9b564..22cf3f51e1cb 100644
--- a/drivers/media/video/mxc/capture/ipu_still.c
+++ b/drivers/media/video/mxc/capture/ipu_still.c
@@ -26,6 +26,9 @@
#include "ipu_prp_sw.h"
static int callback_eof_flag;
+#ifndef CONFIG_MXC_IPU_V1
+static int buffer_num;
+#endif
#ifdef CONFIG_MXC_IPU_V1
static int callback_flag;
@@ -42,10 +45,10 @@ static int callback_flag;
*/
static irqreturn_t prp_csi_eof_callback(int irq, void *dev_id)
{
- if (callback_flag == 2) {
- ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, 0);
+ ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER,
+ callback_flag%2 ? 1 : 0);
+ if (callback_flag == 0)
ipu_enable_channel(CSI_MEM);
- }
callback_flag++;
return IRQ_HANDLED;
@@ -65,9 +68,12 @@ static irqreturn_t prp_still_callback(int irq, void *dev_id)
cam_data *cam = (cam_data *) dev_id;
callback_eof_flag++;
- if (callback_eof_flag < 5)
- ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, 0);
- else {
+ if (callback_eof_flag < 5) {
+#ifndef CONFIG_MXC_IPU_V1
+ buffer_num = (buffer_num == 0) ? 1 : 0;
+ ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, buffer_num);
+#endif
+ } else {
cam->still_counter++;
wake_up_interruptible(&cam->still_queue);
}
@@ -87,6 +93,8 @@ static int prp_still_start(void *private)
u32 pixel_fmt;
int err;
ipu_channel_params_t params;
+ ipu_channel_t channel;
+ int ipu_irq_csi_out_eof;
if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
pixel_fmt = IPU_PIX_FMT_YUV420P;
@@ -113,20 +121,32 @@ static int prp_still_start(void *private)
ipu_csi_enable_mclk_if(CSI_MCLK_RAW, cam->csi, true, true);
+ if (cam->csi == 0) {
+ channel = CSI_MEM0;
+ ipu_irq_csi_out_eof = IPU_IRQ_CSI0_OUT_EOF;
+ }
+ else {
+ channel = CSI_MEM1;
+ ipu_irq_csi_out_eof = IPU_IRQ_CSI1_OUT_EOF;
+ }
+
memset(&params, 0, sizeof(params));
- err = ipu_init_channel(CSI_MEM, &params);
+ params.csi_mem.csi = cam->csi;
+ err = ipu_init_channel(channel, &params);
if (err != 0)
return err;
- err = ipu_init_channel_buffer(CSI_MEM, IPU_OUTPUT_BUFFER,
+ err = ipu_init_channel_buffer(channel, IPU_OUTPUT_BUFFER,
pixel_fmt, cam->v2f.fmt.pix.width,
cam->v2f.fmt.pix.height,
cam->v2f.fmt.pix.width, IPU_ROTATE_NONE,
- cam->still_buf, 0, 0, 0);
+ cam->still_buf[0], cam->still_buf[1],
+ 0, 0);
if (err != 0)
return err;
#ifdef CONFIG_MXC_IPU_V1
+ ipu_clear_irq(IPU_IRQ_SENSOR_OUT_EOF);
err = ipu_request_irq(IPU_IRQ_SENSOR_OUT_EOF, prp_still_callback,
0, "Mxc Camera", cam);
if (err != 0) {
@@ -135,6 +155,7 @@ static int prp_still_start(void *private)
}
callback_flag = 0;
callback_eof_flag = 0;
+ ipu_clear_irq(IPU_IRQ_SENSOR_EOF);
err = ipu_request_irq(IPU_IRQ_SENSOR_EOF, prp_csi_eof_callback,
0, "Mxc Camera", NULL);
if (err != 0) {
@@ -142,8 +163,9 @@ static int prp_still_start(void *private)
return err;
}
#else
- ipu_clear_irq(IPU_IRQ_CSI0_OUT_EOF);
- err = ipu_request_irq(IPU_IRQ_CSI0_OUT_EOF, prp_still_callback,
+
+ ipu_clear_irq(ipu_irq_csi_out_eof);
+ err = ipu_request_irq(ipu_irq_csi_out_eof, prp_still_callback,
0, "Mxc Camera", cam);
if (err != 0) {
printk(KERN_ERR "Error registering irq.\n");
@@ -151,9 +173,9 @@ static int prp_still_start(void *private)
}
callback_eof_flag = 0;
+ ipu_select_buffer(channel, IPU_OUTPUT_BUFFER, 0);
+ ipu_enable_channel(channel);
- ipu_select_buffer(CSI_MEM, IPU_OUTPUT_BUFFER, 0);
- ipu_enable_channel(CSI_MEM);
ipu_enable_csi(cam->csi);
#endif
@@ -170,17 +192,28 @@ static int prp_still_stop(void *private)
{
cam_data *cam = (cam_data *) private;
int err = 0;
+ ipu_channel_t channel;
+ int ipu_irq_csi_out_eof;
+
+ if (cam->csi == 0) {
+ channel = CSI_MEM0;
+ ipu_irq_csi_out_eof = IPU_IRQ_CSI0_OUT_EOF;
+ }
+ else {
+ channel = CSI_MEM1;
+ ipu_irq_csi_out_eof = IPU_IRQ_CSI1_OUT_EOF;
+ }
#ifdef CONFIG_MXC_IPU_V1
ipu_free_irq(IPU_IRQ_SENSOR_EOF, NULL);
ipu_free_irq(IPU_IRQ_SENSOR_OUT_EOF, cam);
#else
- ipu_free_irq(IPU_IRQ_CSI0_OUT_EOF, cam);
+ ipu_free_irq(ipu_irq_csi_out_eof, cam);
#endif
ipu_disable_csi(cam->csi);
- ipu_disable_channel(CSI_MEM, true);
- ipu_uninit_channel(CSI_MEM);
+ ipu_disable_channel(channel, true);
+ ipu_uninit_channel(channel);
ipu_csi_enable_mclk_if(CSI_MCLK_RAW, cam->csi, false, false);
return err;
diff --git a/drivers/media/video/mxc/capture/mt9v111.c b/drivers/media/video/mxc/capture/mt9v111.c
index c95a20683924..dfdd455db3dd 100644
--- a/drivers/media/video/mxc/capture/mt9v111.c
+++ b/drivers/media/video/mxc/capture/mt9v111.c
@@ -18,6 +18,9 @@
*
* @ingroup Camera
*/
+
+//#define MT9V111_DEBUG
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -40,7 +43,6 @@ static mt9v111_conf mt9v111_device;
/*!
* Holds the current frame rate.
*/
-static int reset_frame_rate = MT9V111_FRAME_RATE;
struct sensor {
const struct mt9v111_platform_data *platform_data;
@@ -49,33 +51,45 @@ struct sensor {
struct v4l2_pix_format pix;
struct v4l2_captureparm streamcap;
bool on;
+ bool used;
/* control settings */
int brightness;
- int hue;
- int contrast;
int saturation;
- int red;
- int green;
- int blue;
+ int sharpness;
+ int gain;
int ae_mode;
-} mt9v111_data;
-
-extern void gpio_sensor_active(void);
-extern void gpio_sensor_inactive(void);
+};
static int mt9v111_probe(struct i2c_client *client,
const struct i2c_device_id *id);
static int mt9v111_remove(struct i2c_client *client);
static const struct i2c_device_id mt9v111_id[] = {
- {"mt9v111", 0},
+ {"mt9v111_1", 2},
+ {"mt9v111_2", 3},
{},
};
+struct sensor mt9v111_data[ARRAY_SIZE(mt9v111_id)-1];
+
MODULE_DEVICE_TABLE(i2c, mt9v111_id);
+static int mt9v111_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ pr_debug("In mt9v111_suspend\n");
+
+ return 0;
+}
+
+static int mt9v111_resume(struct i2c_client *client)
+{
+ pr_debug("In mt9v111_resume\n");
+
+ return 0;
+}
+
static struct i2c_driver mt9v111_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
@@ -84,37 +98,52 @@ static struct i2c_driver mt9v111_i2c_driver = {
.probe = mt9v111_probe,
.remove = mt9v111_remove,
.id_table = mt9v111_id,
-/* To add power management add .suspend and .resume functions */
+ .suspend = mt9v111_suspend,
+ .resume = mt9v111_resume,
};
/*
* Function definitions
*/
-#ifdef MT9V111_DEBUG
-static inline int mt9v111_read_reg(u8 reg)
+static int mt9v111_id_from_name ( const char * name )
+{
+ int id = -1;
+
+ if( name == NULL || ( strlen(name) < strlen("mt9v111_n") ) )
+ return -1;
+
+ id = (int)simple_strtol(name+strlen("mt9v111_"),NULL,0) - 1;
+ if( id >= ARRAY_SIZE(mt9v111_id) ) {
+ printk("Invalid sensor index %d for %s\n",id,name);
+ return -1;
+ }
+
+ return id;
+}
+
+static inline int mt9v111_read_reg(int sensorid , u8 reg)
{
- int val = i2c_smbus_read_word_data(mt9v111_data.i2c_client, reg);
+ int val = i2c_smbus_read_word_data(mt9v111_data[sensorid].i2c_client, reg);
if (val != -1)
val = cpu_to_be16(val);
return val;
}
-#endif
/*!
* Writes to the register via I2C.
*/
-static inline int mt9v111_write_reg(u8 reg, u16 val)
+static inline int mt9v111_write_reg(int sensorid , u8 reg, u16 val)
{
- pr_debug("In mt9v111_write_reg (0x%x, 0x%x)\n", reg, val);
+ pr_debug("[%d] In mt9v111_write_reg (0x%x, 0x%x)\n", sensorid , reg, val);
pr_debug(" write reg %x val %x.\n", reg, val);
- return i2c_smbus_write_word_data(mt9v111_data.i2c_client,
+ return i2c_smbus_write_word_data(mt9v111_data[sensorid].i2c_client,
reg, cpu_to_be16(val));
}
/*!
- * Initialize mt9v111_sensor_lib
+ * Initialize mt9v111_sensor_lib_datasheet
* Libarary for Sensor configuration through I2C
*
* @param coreReg Core Registers
@@ -122,7 +151,7 @@ static inline int mt9v111_write_reg(u8 reg, u16 val)
*
* @return status
*/
-static u8 mt9v111_sensor_lib(mt9v111_coreReg * coreReg, mt9v111_IFPReg * ifpReg)
+static u8 mt9v111_sensor_lib_datasheet(int sensorid , mt9v111_coreReg * coreReg, mt9v111_IFPReg * ifpReg)
{
u8 reg;
u16 data;
@@ -130,200 +159,103 @@ static u8 mt9v111_sensor_lib(mt9v111_coreReg * coreReg, mt9v111_IFPReg * ifpReg)
pr_debug("In mt9v111_sensor_lib\n");
+ /* IFP R51(0x33)=5137,R57(0x39)=290,R59(0x3B)=1068,R62(0x3E)=4095,R89(0x59)=504,R90(0x5A)=605,R92(0x5C)=8222,R93(0x5D)=10021,R100(0x64)=4477 */
+
/*
* setup to IFP registers
*/
reg = MT9V111I_ADDR_SPACE_SEL;
data = ifpReg->addrSpaceSel;
- mt9v111_write_reg(reg, data);
-
- /* Operation Mode Control */
- reg = MT9V111I_MODE_CONTROL;
- data = ifpReg->modeControl;
- mt9v111_write_reg(reg, data);
-
- /* Output format */
- reg = MT9V111I_FORMAT_CONTROL;
- data = ifpReg->formatControl; /* Set bit 12 */
- mt9v111_write_reg(reg, data);
-
- /* AE limit 4 */
- reg = MT9V111I_SHUTTER_WIDTH_LIMIT_AE;
- data = ifpReg->gainLimitAE;
- mt9v111_write_reg(reg, data);
-
- reg = MT9V111I_OUTPUT_FORMAT_CTRL2;
- data = ifpReg->outputFormatCtrl2;
- mt9v111_write_reg(reg, data);
-
- reg = MT9V111I_AE_SPEED;
- data = ifpReg->AESpeed;
- mt9v111_write_reg(reg, data);
-
- /* output image size */
- reg = MT9V111i_H_PAN;
- data = 0x8000 | ifpReg->HPan;
- mt9v111_write_reg(reg, data);
-
- reg = MT9V111i_H_ZOOM;
- data = 0x8000 | ifpReg->HZoom;
- mt9v111_write_reg(reg, data);
-
- reg = MT9V111i_H_SIZE;
- data = 0x8000 | ifpReg->HSize;
- mt9v111_write_reg(reg, data);
-
- reg = MT9V111i_V_PAN;
- data = 0x8000 | ifpReg->VPan;
- mt9v111_write_reg(reg, data);
+ mt9v111_write_reg(sensorid,reg, data);
- reg = MT9V111i_V_ZOOM;
- data = 0x8000 | ifpReg->VZoom;
- mt9v111_write_reg(reg, data);
+ reg = MT9V111I_LIMIT_SHARP_SATU_CTRL;
+ data = ifpReg->limitSharpSatuCtrl;
+ mt9v111_write_reg(sensorid,reg, data);
- reg = MT9V111i_V_SIZE;
- data = 0x8000 | ifpReg->VSize;
- mt9v111_write_reg(reg, data);
-
- reg = MT9V111i_H_PAN;
- data = ~0x8000 & ifpReg->HPan;
- mt9v111_write_reg(reg, data);
-#if 0
reg = MT9V111I_UPPER_SHUTTER_DELAY_LIM;
data = ifpReg->upperShutterDelayLi;
- mt9v111_write_reg(reg, data);
+ mt9v111_write_reg(sensorid,reg, data);
+
+ reg = MT9V111I_IPF_BLACK_LEVEL_SUB;
+ data = ifpReg->ipfBlackLevelSub;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ reg = MT9V111I_GAIN_THRE_CCAM_ADJ;
+ data = ifpReg->agimnThreCamAdj;
+ mt9v111_write_reg(sensorid,reg, data);
reg = MT9V111I_SHUTTER_60;
data = ifpReg->shutter_width_60;
- mt9v111_write_reg(reg, data);
+ mt9v111_write_reg(sensorid,reg, data);
+
+ reg = MT9V111I_AUTO_EXPOSURE_17;
+ data = ifpReg->auto_exposure_17;
+ mt9v111_write_reg(sensorid,reg, data);
reg = MT9V111I_SEARCH_FLICK_60;
data = ifpReg->search_flicker_60;
- mt9v111_write_reg(reg, data);
-#endif
+ mt9v111_write_reg(sensorid,reg, data);
+
+ reg = MT9V111I_RESERVED93;
+ data = ifpReg->reserved93;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ reg = MT9V111I_RESERVED100;
+ data = ifpReg->reserved100;
+ mt9v111_write_reg(sensorid,reg, data);
/*
* setup to sensor core registers
*/
reg = MT9V111I_ADDR_SPACE_SEL;
data = coreReg->addressSelect;
- mt9v111_write_reg(reg, data);
-
- /* enable changes and put the Sync bit on */
- reg = MT9V111S_OUTPUT_CTRL;
- data = MT9V111S_OUTCTRL_SYNC | MT9V111S_OUTCTRL_CHIP_ENABLE | 0x3000;
- mt9v111_write_reg(reg, data);
+ mt9v111_write_reg(sensorid,reg, data);
- /* min PIXCLK - Default */
- reg = MT9V111S_PIXEL_CLOCK_SPEED;
- data = coreReg->pixelClockSpeed;
- mt9v111_write_reg(reg, data);
+ /* Core R5=46, R7[4]=0 (DEFAULT) ,R33=58369*/
- /* Setup image flipping / Dark rows / row/column skip */
- reg = MT9V111S_READ_MODE;
- data = coreReg->readMode;
- mt9v111_write_reg(reg, data);
-
- /* zoom 0 */
- reg = MT9V111S_DIGITAL_ZOOM;
- data = coreReg->digitalZoom;
- mt9v111_write_reg(reg, data);
-
- /* min H-blank */
reg = MT9V111S_HOR_BLANKING;
data = coreReg->horizontalBlanking;
- mt9v111_write_reg(reg, data);
-
- /* min V-blank */
- reg = MT9V111S_VER_BLANKING;
- data = coreReg->verticalBlanking;
- mt9v111_write_reg(reg, data);
-
- reg = MT9V111S_SHUTTER_WIDTH;
- data = coreReg->shutterWidth;
- mt9v111_write_reg(reg, data);
+ mt9v111_write_reg(sensorid,reg, data);
- reg = MT9V111S_SHUTTER_DELAY;
- data = ifpReg->upperShutterDelayLi;
- mt9v111_write_reg(reg, data);
-
- /* changes become effective */
- reg = MT9V111S_OUTPUT_CTRL;
- data = MT9V111S_OUTCTRL_CHIP_ENABLE | 0x3000;
- mt9v111_write_reg(reg, data);
+ reg = MT9V111S_RESERVED33;
+ data = coreReg->reserved33;
+ mt9v111_write_reg(sensorid,reg, data);
return error;
}
-/*!
- * MT9V111 frame rate calculate
- *
- * @param frame_rate int *
- * @param mclk int
- * @return None
- */
-static void mt9v111_rate_cal(int *frame_rate, int mclk)
+void mt9v111_config_datasheet(void)
{
- int num_clock_per_row;
- int max_rate = 0;
+ pr_debug("In mt9v111_config_datasheet\n");
- pr_debug("In mt9v111_rate_cal\n");
+ mt9v111_device.coreReg->addressSelect = MT9V111I_SEL_SCA;
- num_clock_per_row = (MT9V111_MAX_WIDTH + 114 + MT9V111_HORZBLANK_MIN)
- * 2;
- max_rate = mclk / (num_clock_per_row *
- (MT9V111_MAX_HEIGHT + MT9V111_VERTBLANK_DEFAULT));
+ /* MT9V111I_ADDR_SPACE_SEL */
+ mt9v111_device.ifpReg->addrSpaceSel = MT9V111I_SEL_IFP;
- if ((*frame_rate > max_rate) || (*frame_rate == 0)) {
- *frame_rate = max_rate;
- }
+ /* Recommended values for 30fps @ 27MHz from datasheet*/
- mt9v111_device.coreReg->verticalBlanking
- = mclk / (*frame_rate * num_clock_per_row) - MT9V111_MAX_HEIGHT;
+ /* Core R5=132, R6=10 , R7[4]=0 (DEFAULT) ,R33=58369*/
- reset_frame_rate = *frame_rate;
-}
+ mt9v111_device.coreReg->horizontalBlanking = 132;
+ mt9v111_device.coreReg->verticalBlanking = 10;
+ mt9v111_device.coreReg->reserved33 = 58369;
-/*!
- * MT9V111 sensor configuration
- */
-void mt9v111_config(void)
-{
- pr_debug("In mt9v111_config\n");
+ /* IFP R51(0x33)=5137,R57(0x39)=290,R59(0x3B)=1068,R62(0x3E)=4095,R89(0x59)=504,R90(0x5A)=605,R92(0x5C)=8222,R93(0x5D)=10021,R100(0x64)=4477 */
- mt9v111_device.coreReg->addressSelect = MT9V111I_SEL_SCA;
- mt9v111_device.ifpReg->addrSpaceSel = MT9V111I_SEL_IFP;
+ mt9v111_device.ifpReg->limitSharpSatuCtrl = 5137;
+ mt9v111_device.ifpReg->upperShutterDelayLi = 290;
+ mt9v111_device.ifpReg->ipfBlackLevelSub = 1068;
+ mt9v111_device.ifpReg->agimnThreCamAdj = 4095;
- mt9v111_device.coreReg->windowHeight = MT9V111_WINHEIGHT;
- mt9v111_device.coreReg->windowWidth = MT9V111_WINWIDTH;
- mt9v111_device.coreReg->zoomColStart = 0;
- mt9v111_device.coreReg->zomRowStart = 0;
- mt9v111_device.coreReg->digitalZoom = 0x0;
-
- mt9v111_device.coreReg->verticalBlanking = MT9V111_VERTBLANK_DEFAULT;
- mt9v111_device.coreReg->horizontalBlanking = MT9V111_HORZBLANK_MIN;
- mt9v111_device.coreReg->pixelClockSpeed = 0;
- mt9v111_device.coreReg->readMode = 0xd0a1;
-
- mt9v111_device.ifpReg->outputFormatCtrl2 = 0;
- mt9v111_device.ifpReg->gainLimitAE = 0x300;
- mt9v111_device.ifpReg->AESpeed = 0x80;
-
- /* here is the default value */
- mt9v111_device.ifpReg->formatControl = 0xc800;
- mt9v111_device.ifpReg->modeControl = 0x708e;
- mt9v111_device.ifpReg->awbSpeed = 0x4514;
- mt9v111_device.coreReg->shutterWidth = 0xf8;
-
- /* output size */
- mt9v111_device.ifpReg->HPan = 0;
- mt9v111_device.ifpReg->HZoom = MT9V111_MAX_WIDTH;
- mt9v111_device.ifpReg->HSize = MT9V111_MAX_WIDTH;
- mt9v111_device.ifpReg->VPan = 0;
- mt9v111_device.ifpReg->VZoom = MT9V111_MAX_HEIGHT;
- mt9v111_device.ifpReg->VSize = MT9V111_MAX_HEIGHT;
+ mt9v111_device.ifpReg->shutter_width_60 = 504;
+ mt9v111_device.ifpReg->auto_exposure_17 = 605;
+ mt9v111_device.ifpReg->search_flicker_60 = 8222;
+ mt9v111_device.ifpReg->reserved93 = 10021;
+ mt9v111_device.ifpReg->reserved100 = 4477;
}
+
/*!
* mt9v111 sensor set saturtionn
*
@@ -331,7 +263,7 @@ void mt9v111_config(void)
* @return Error code of 0.
*/
-static int mt9v111_set_saturation(int saturation)
+static int mt9v111_set_saturation(int sensorid , int saturation)
{
u8 reg;
u16 data;
@@ -357,6 +289,9 @@ static int mt9v111_set_saturation(int saturation)
case 25:
mt9v111_device.ifpReg->awbSpeed = 0x6514;
break;
+ case 0:
+ mt9v111_device.ifpReg->awbSpeed = 0x7514;
+ break;
default:
mt9v111_device.ifpReg->awbSpeed = 0x4514;
break;
@@ -364,12 +299,348 @@ static int mt9v111_set_saturation(int saturation)
reg = MT9V111I_ADDR_SPACE_SEL;
data = mt9v111_device.ifpReg->addrSpaceSel;
- mt9v111_write_reg(reg, data);
+ mt9v111_write_reg(sensorid,reg, data);
/* Operation Mode Control */
reg = MT9V111I_AWB_SPEED;
data = mt9v111_device.ifpReg->awbSpeed;
- mt9v111_write_reg(reg, data);
+ mt9v111_write_reg(sensorid,reg, data);
+
+ return 0;
+}
+
+#if 0
+/*!
+ * mt9v111 sensor set digital zoom
+ *
+ * @param on/off int
+
+ * @return 0 on success, -1 on error.
+ */
+static int mt9v111_set_digitalzoom(int sensorid , unsigned int on)
+{
+ u8 reg;
+ u16 data;
+ pr_debug("In mt9v111_set_digitalzoom(%d)\n",on);
+
+ if( on > 1 )
+ return -1;
+
+ mt9v111_device.coreReg->digitalZoom = on;
+
+ reg = MT9V111I_ADDR_SPACE_SEL;
+ data = mt9v111_device.coreReg->addressSelect;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ /* Operation Mode Control */
+ reg = MT9V111S_DIGITAL_ZOOM;
+ data = mt9v111_device.coreReg->digitalZoom;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ return 0;
+}
+
+/*!
+ * mt9v111 sensor set digital pan
+ *
+ * @param pan_level int
+
+ * @return 0 on success, -1 on error.
+ */
+static int mt9v111_set_digitalpan (int sensorid , int pan_level)
+{
+ u8 reg;
+ u16 data;
+ pr_debug("In mt9v111_set_digitalpan(%d)\n",
+ pan_level);
+
+ mt9v111_device.ifpReg->HPan = 8;
+ if (pan_level & 0xFFFF0000) {
+ pan_level = (0xFFFFFFFF - pan_level);
+ pan_level = pan_level / 0x14;
+ mt9v111_device.ifpReg->HPan =
+ mt9v111_device.ifpReg->HPan - (pan_level & 0x3FF);
+ } else {
+ pan_level = pan_level / 0x14;
+ mt9v111_device.ifpReg->HPan =
+ mt9v111_device.ifpReg->HPan + (pan_level - 1);
+ }
+
+ reg = MT9V111I_ADDR_SPACE_SEL;
+ data = mt9v111_device.ifpReg->addrSpaceSel;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ /* Operation Mode Control */
+ reg = MT9V111i_H_PAN;
+ data = mt9v111_device.ifpReg->HPan;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ return 0;
+}
+
+/*!
+ * mt9v111 sensor set digital tilt
+ *
+ * @param tilt_level int
+
+ * @return 0 on success, -1 on error.
+ */
+static int mt9v111_set_digitaltilt (int sensorid , int tilt_level)
+{
+ u8 reg;
+ u16 data;
+ pr_debug("In mt9v111_set_digitaltilt(%d)\n",
+ tilt_level);
+
+ mt9v111_device.ifpReg->VPan = 8;
+ if( tilt_level & 0xFFFF0000 ) {
+ tilt_level = (0xFFFFFFFF - tilt_level);
+ tilt_level = tilt_level / 0x14;
+ mt9v111_device.ifpReg->VPan = mt9v111_device.ifpReg->VPan - (tilt_level & 0x3FF);
+ }
+ else {
+ tilt_level = tilt_level / 0x14;
+ mt9v111_device.ifpReg->VPan = mt9v111_device.ifpReg->VPan + (tilt_level - 1);
+ }
+
+ reg = MT9V111I_ADDR_SPACE_SEL;
+ data = mt9v111_device.ifpReg->addrSpaceSel;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ /* Operation Mode Control */
+ reg = MT9V111i_V_PAN;
+ data = mt9v111_device.ifpReg->VPan;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ return 0;
+}
+
+/*!
+ * mt9v111 sensor set output resolution
+ *
+ * @param resolution res
+
+ * @return 0 on success, -1 on error.
+ */
+static int mt9v111_set_outputresolution(int sensorid , MT9V111_OutputResolution res)
+{
+ u8 reg;
+ u16 data;
+ int zoom = 0;
+
+ pr_debug("In mt9v111_set_outputresolution(%d)\n",res);
+
+ switch (res) {
+ case MT9V111_OutputResolution_VGA:
+ /* 640x480 */
+ mt9v111_device.ifpReg->HSize = 0x0280;
+ mt9v111_device.ifpReg->VSize = 0x01E0;
+ break;
+
+ case MT9V111_OutputResolution_QVGA:
+ /* 320x240 */
+ mt9v111_device.ifpReg->HSize = 0x0140;
+ mt9v111_device.ifpReg->VSize = 0x00F0;
+ break;
+
+ case MT9V111_OutputResolution_CIF:
+ /* 352x288 */
+ mt9v111_device.ifpReg->HSize = 0x0160;
+ mt9v111_device.ifpReg->VSize = 0x0120;
+ mt9v111_device.ifpReg->HZoom = 0x0160;
+ mt9v111_device.ifpReg->VZoom = 0x0120;
+ zoom = 1;
+ break;
+
+ case MT9V111_OutputResolution_QCIF:
+ /* 176X220 */
+ mt9v111_device.ifpReg->HSize = 0x00B0;
+ mt9v111_device.ifpReg->VSize = 0x0090;
+ mt9v111_device.ifpReg->HZoom = 0x00B0;
+ mt9v111_device.ifpReg->VZoom = 0x0090;
+ zoom = 1;
+ break;
+
+ case MT9V111_OutputResolution_QQVGA:
+ /* 2048*1536 */
+ mt9v111_device.ifpReg->HSize = 0x00A0;
+ mt9v111_device.ifpReg->VSize = 0x0078;
+ mt9v111_device.ifpReg->HZoom = 0x00A0;
+ mt9v111_device.ifpReg->VZoom = 0x0078;
+ zoom = 1;
+ break;
+
+ case MT9V111_OutputResolution_SXGA:
+ /* 1280x1024 */
+ break;
+
+ default:
+ break;
+ }
+
+ reg = MT9V111I_ADDR_SPACE_SEL;
+ data = mt9v111_device.ifpReg->addrSpaceSel;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ reg = MT9V111i_V_SIZE;
+ data = mt9v111_device.ifpReg->VSize;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ reg = MT9V111i_H_SIZE;
+ data = mt9v111_device.ifpReg->HSize;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ if ( zoom ) {
+ reg = MT9V111i_V_ZOOM;
+ data = mt9v111_device.ifpReg->VZoom;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ reg = MT9V111i_H_ZOOM;
+ data = mt9v111_device.ifpReg->HZoom;
+ mt9v111_write_reg(sensorid,reg, data);
+ }
+
+ return 0;
+}
+
+/*!
+ * mt9v111 sensor set digital flash
+ *
+ * @param flash_level int
+
+ * @return 0 on success, -1 on error.
+ */
+static int mt9v111_set_digitalflash (int sensorid , int flash_level)
+{
+ u8 reg;
+ u16 data = mt9v111_read_reg(sensorid,MT9V111i_FLASH_CTRL);
+ pr_debug("In mt9v111_set_digitalflash(%d)\n",
+ flash_level);
+
+ if(flash_level) {
+ data &= (0xFF00);
+ data |= ((flash_level & 0x00FF) | (1<<13));
+ }
+ else {
+ data &= ~(1<<13);
+ }
+
+ reg = MT9V111I_ADDR_SPACE_SEL;
+ data = mt9v111_device.ifpReg->addrSpaceSel;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ /* Operation Mode Control */
+ reg = MT9V111i_FLASH_CTRL;
+ mt9v111_device.ifpReg->flashCtrl = data;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ return 0;
+}
+
+/*!
+ * mt9v111 sensor set digital monochrome
+ *
+ * @param on int
+
+ * @return 0 on success, -1 on error.
+ */
+static int mt9v111_set_digitalmonochrome (int sensorid , int on)
+{
+ u8 reg;
+ u16 data = mt9v111_read_reg(sensorid,MT9V111I_FORMAT_CONTROL);
+ pr_debug("In mt9v111_set_digitalmonochrome(%d)\n",
+ on);
+
+ /* clear the monochrome bit field */
+ data &= ~(1<<5);
+
+ /* enable or disable monochrome mode */
+ if( on )
+ data |= (0<<5);
+ else
+ data |= (1<<5);
+
+ reg = MT9V111I_ADDR_SPACE_SEL;
+ data = mt9v111_device.ifpReg->addrSpaceSel;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ /* Operation Mode Control */
+ reg = MT9V111I_FORMAT_CONTROL;
+ mt9v111_device.ifpReg->formatControl = data;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ return 0;
+}
+#endif
+
+/*!
+ * mt9v111 sensor set digital sharpness
+ *
+ * @param value int
+
+ * @return 0 on success, -1 on error.
+ */
+static int mt9v111_set_digitalsharpness (int sensorid , int value)
+{
+ u8 reg;
+ u16 data ;
+
+ pr_debug("In mt9v111_set_digitalsharpness(%d)\n",value);
+
+ reg = MT9V111I_ADDR_SPACE_SEL;
+ data = mt9v111_device.ifpReg->addrSpaceSel;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ data = mt9v111_read_reg(sensorid,MT9V111I_APERTURE_GAIN);
+
+ /* erase current and remove auto reduce sharpness in low light */
+ data &= ~(0x000F);
+ data |= (value & (0x000F));
+ if( data > (0x000F) )
+ return -1;
+
+ /* Operation Mode Control */
+ reg = MT9V111I_APERTURE_GAIN;
+ mt9v111_device.ifpReg->apertureGain = data;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ return 0;
+}
+
+/*!
+ * mt9v111 sensor set digital brightness
+ *
+ * @param value int
+
+ * @return 0 on success, -1 on error.
+ */
+static int mt9v111_set_digitalbrightness (int sensorid , int value)
+{
+ u8 reg;
+ u16 data;
+ u32 max_brightness, min_brightness;
+
+ data = mt9v111_read_reg(sensorid,MT9V111I_CLIP_LIMIT_OUTPUT_LUMI);
+ max_brightness = data >> 8;
+ min_brightness = (u8)data;
+
+ if( value > max_brightness )
+ value = max_brightness;
+ else if( value < min_brightness )
+ value = min_brightness;
+
+ reg = MT9V111I_ADDR_SPACE_SEL;
+ data = mt9v111_device.ifpReg->addrSpaceSel;
+ mt9v111_write_reg(sensorid,reg, data);
+
+ data = mt9v111_read_reg(sensorid,MT9V111I_AE_PRECISION_TARGET);
+ data &= 0xFF00; /* Clear target luminance */
+ data |= ((u8)value );
+
+ /* Operation Mode Control */
+ reg = MT9V111I_AE_PRECISION_TARGET;
+ mt9v111_device.ifpReg->AEPrecisionTarget = data;
+ mt9v111_write_reg(sensorid,reg, data);
return 0;
}
@@ -380,7 +651,7 @@ static int mt9v111_set_saturation(int saturation)
* @param ae_mode int
* @return Error code of 0 (no Error)
*/
-static int mt9v111_set_ae_mode(int ae_mode)
+static int mt9v111_set_ae_mode(int sensorid , int ae_mode)
{
u8 reg;
u16 data;
@@ -408,19 +679,20 @@ static int mt9v111_set_ae_mode(int ae_mode)
/* V4L2_EXPOSURE_MANUAL = 1 needs register setting of 0x308E */
mt9v111_device.ifpReg->modeControl &= 0x3fff;
mt9v111_device.ifpReg->modeControl |= (ae_mode & 0x03) << 14;
- mt9v111_data.ae_mode = ae_mode;
+ mt9v111_data[sensorid].ae_mode = ae_mode;
reg = MT9V111I_ADDR_SPACE_SEL;
data = mt9v111_device.ifpReg->addrSpaceSel;
- mt9v111_write_reg(reg, data);
+ mt9v111_write_reg(sensorid,reg, data);
reg = MT9V111I_MODE_CONTROL;
data = mt9v111_device.ifpReg->modeControl;
- mt9v111_write_reg(reg, data);
+ mt9v111_write_reg(sensorid,reg, data);
return 0;
}
+#if 0
/*!
* mt9v111 sensor get AE measurement window mode configuration
*
@@ -435,6 +707,7 @@ static void mt9v111_get_ae_mode(int *ae_mode)
*ae_mode = (mt9v111_device.ifpReg->modeControl & 0xc) >> 2;
}
}
+#endif
#ifdef MT9V111_DEBUG
/*!
@@ -442,33 +715,33 @@ static void mt9v111_get_ae_mode(int *ae_mode)
*
* @return none
*/
-static void mt9v111_test_pattern(bool flag)
+static void mt9v111_test_pattern(int sensorid , bool flag)
{
u16 data;
/* switch to sensor registers */
- mt9v111_write_reg(MT9V111I_ADDR_SPACE_SEL, MT9V111I_SEL_SCA);
+ mt9v111_write_reg(sensorid,MT9V111I_ADDR_SPACE_SEL, MT9V111I_SEL_SCA);
if (flag == true) {
testpattern = MT9V111S_OUTCTRL_TEST_MODE;
- data = mt9v111_read_reg(MT9V111S_ROW_NOISE_CTRL) & 0xBF;
- mt9v111_write_reg(MT9V111S_ROW_NOISE_CTRL, data);
+ data = mt9v111_read_reg(sensorid,MT9V111S_ROW_NOISE_CTRL) & 0xBF;
+ mt9v111_write_reg(sensorid,MT9V111S_ROW_NOISE_CTRL, data);
- mt9v111_write_reg(MT9V111S_TEST_DATA, 0);
+ mt9v111_write_reg(sensorid,MT9V111S_TEST_DATA, 0);
/* changes take effect */
data = MT9V111S_OUTCTRL_CHIP_ENABLE | testpattern | 0x3000;
- mt9v111_write_reg(MT9V111S_OUTPUT_CTRL, data);
+ mt9v111_write_reg(sensorid,MT9V111S_OUTPUT_CTRL, data);
} else {
testpattern = 0;
- data = mt9v111_read_reg(MT9V111S_ROW_NOISE_CTRL) | 0x40;
+ data = mt9v111_read_reg(sensorid,MT9V111S_ROW_NOISE_CTRL) | 0x40;
mt9v111_write_reg(MT9V111S_ROW_NOISE_CTRL, data);
/* changes take effect */
data = MT9V111S_OUTCTRL_CHIP_ENABLE | testpattern | 0x3000;
- mt9v111_write_reg(MT9V111S_OUTPUT_CTRL, data);
+ mt9v111_write_reg(sensorid,MT9V111S_OUTPUT_CTRL, data);
}
}
#endif
@@ -507,6 +780,7 @@ static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
p->u.bt656.clock_curr = MT9V111_MCLK;
p->if_type = V4L2_IF_TYPE_BT656;
p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT;
+ p->u.bt656.bt_sync_correct = 1; // translates to CSI ext vsync
p->u.bt656.clock_min = MT9V111_CLK_MIN;
p->u.bt656.clock_max = MT9V111_CLK_MAX;
@@ -534,10 +808,12 @@ static int ioctl_s_power(struct v4l2_int_device *s, int on)
sensor->on = on;
- if (on)
- gpio_sensor_active();
- else
- gpio_sensor_inactive();
+ if(on) {
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */, true, true);
+ }
+ else {
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */, false, false);
+ }
return 0;
}
@@ -554,19 +830,23 @@ static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
int ret = 0;
struct v4l2_captureparm *cparm = &a->parm.capture;
/* s->priv points to mt9v111_data */
+ int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name);
pr_debug("In mt9v111:ioctl_g_parm\n");
+ if( sensorid < 0 )
+ return ret;
+
switch (a->type) {
/* This is the only case currently handled. */
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
pr_debug(" type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
memset(a, 0, sizeof(*a));
a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- cparm->capability = mt9v111_data.streamcap.capability;
+ cparm->capability = mt9v111_data[sensorid].streamcap.capability;
cparm->timeperframe =
- mt9v111_data.streamcap.timeperframe;
- cparm->capturemode = mt9v111_data.streamcap.capturemode;
+ mt9v111_data[sensorid].streamcap.timeperframe;
+ cparm->capturemode = mt9v111_data[sensorid].streamcap.capturemode;
ret = 0;
break;
@@ -605,9 +885,13 @@ static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
int ret = 0;
struct v4l2_captureparm *cparm = &a->parm.capture;
/* s->priv points to mt9v111_data */
+ int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name);
pr_debug("In mt9v111:ioctl_s_parm\n");
+ if( sensorid < 0 )
+ return ret;
+
switch (a->type) {
/* This is the only case currently handled. */
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -617,13 +901,13 @@ static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
* Changing the frame rate is not allowed on this
*camera. */
if (cparm->timeperframe.denominator !=
- mt9v111_data.streamcap.timeperframe.denominator) {
+ mt9v111_data[sensorid].streamcap.timeperframe.denominator) {
pr_err("ERROR: mt9v111: ioctl_s_parm: " \
"This camera does not allow frame rate "
"changes.\n");
ret = -EINVAL;
} else {
- mt9v111_data.streamcap.timeperframe =
+ mt9v111_data[sensorid].streamcap.timeperframe =
cparm->timeperframe;
/* Call any camera functions to match settings. */
}
@@ -635,7 +919,7 @@ static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
"unsupported capture mode\n");
ret = -EINVAL;
} else {
- mt9v111_data.streamcap.capturemode =
+ mt9v111_data[sensorid].streamcap.capturemode =
cparm->capturemode;
/* Call any camera functions to match settings. */
/* Right now this camera only supports 1 mode. */
@@ -685,6 +969,7 @@ static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
return 0;
}
+#if 0
/*!
* ioctl_queryctrl - V4L2 sensor interface handler for VIDIOC_QUERYCTRL ioctl
* @s: pointer to standard V4L2 device structure
@@ -700,6 +985,7 @@ static int ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qc)
return 0;
}
+#endif
/*!
* ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
@@ -712,66 +998,29 @@ static int ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qc)
*/
static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
{
+ int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name);
+
pr_debug("In mt9v111:ioctl_g_ctrl\n");
+ if( sensorid < 0 )
+ return 0;
+
switch (vc->id) {
case V4L2_CID_BRIGHTNESS:
pr_debug(" V4L2_CID_BRIGHTNESS\n");
- vc->value = mt9v111_data.brightness;
- break;
- case V4L2_CID_CONTRAST:
- pr_debug(" V4L2_CID_CONTRAST\n");
- vc->value = mt9v111_data.contrast;
+ vc->value = mt9v111_data[sensorid].brightness;
break;
case V4L2_CID_SATURATION:
pr_debug(" V4L2_CID_SATURATION\n");
- vc->value = mt9v111_data.saturation;
- break;
- case V4L2_CID_HUE:
- pr_debug(" V4L2_CID_HUE\n");
- vc->value = mt9v111_data.hue;
- break;
- case V4L2_CID_AUTO_WHITE_BALANCE:
- pr_debug(
- " V4L2_CID_AUTO_WHITE_BALANCE\n");
- vc->value = 0;
- break;
- case V4L2_CID_DO_WHITE_BALANCE:
- pr_debug(
- " V4L2_CID_DO_WHITE_BALANCE\n");
- vc->value = 0;
- break;
- case V4L2_CID_RED_BALANCE:
- pr_debug(" V4L2_CID_RED_BALANCE\n");
- vc->value = mt9v111_data.red;
- break;
- case V4L2_CID_BLUE_BALANCE:
- pr_debug(" V4L2_CID_BLUE_BALANCE\n");
- vc->value = mt9v111_data.blue;
- break;
- case V4L2_CID_GAMMA:
- pr_debug(" V4L2_CID_GAMMA\n");
- vc->value = 0;
+ vc->value = mt9v111_data[sensorid].saturation;
break;
case V4L2_CID_EXPOSURE:
pr_debug(" V4L2_CID_EXPOSURE\n");
- vc->value = mt9v111_data.ae_mode;
- break;
- case V4L2_CID_AUTOGAIN:
- pr_debug(" V4L2_CID_AUTOGAIN\n");
- vc->value = 0;
+ vc->value = mt9v111_data[sensorid].ae_mode;
break;
case V4L2_CID_GAIN:
pr_debug(" V4L2_CID_GAIN\n");
- vc->value = 0;
- break;
- case V4L2_CID_HFLIP:
- pr_debug(" V4L2_CID_HFLIP\n");
- vc->value = 0;
- break;
- case V4L2_CID_VFLIP:
- pr_debug(" V4L2_CID_VFLIP\n");
- vc->value = 0;
+ vc->value = mt9v111_data[sensorid].gain;
break;
default:
pr_debug(" Default case\n");
@@ -794,56 +1043,34 @@ static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
{
int retval = 0;
+ int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name);
pr_debug("In mt9v111:ioctl_s_ctrl %d\n",
vc->id);
+ if( sensorid < 0 )
+ return retval;
+
switch (vc->id) {
case V4L2_CID_BRIGHTNESS:
pr_debug(" V4L2_CID_BRIGHTNESS\n");
- break;
- case V4L2_CID_CONTRAST:
- pr_debug(" V4L2_CID_CONTRAST\n");
+ mt9v111_set_digitalbrightness(sensorid,vc->value);
+ mt9v111_data[sensorid].brightness = vc->value;
break;
case V4L2_CID_SATURATION:
pr_debug(" V4L2_CID_SATURATION\n");
- retval = mt9v111_set_saturation(vc->value);
- break;
- case V4L2_CID_HUE:
- pr_debug(" V4L2_CID_HUE\n");
- break;
- case V4L2_CID_AUTO_WHITE_BALANCE:
- pr_debug(
- " V4L2_CID_AUTO_WHITE_BALANCE\n");
- break;
- case V4L2_CID_DO_WHITE_BALANCE:
- pr_debug(
- " V4L2_CID_DO_WHITE_BALANCE\n");
- break;
- case V4L2_CID_RED_BALANCE:
- pr_debug(" V4L2_CID_RED_BALANCE\n");
- break;
- case V4L2_CID_BLUE_BALANCE:
- pr_debug(" V4L2_CID_BLUE_BALANCE\n");
- break;
- case V4L2_CID_GAMMA:
- pr_debug(" V4L2_CID_GAMMA\n");
+ retval = mt9v111_set_saturation(sensorid,vc->value);
+ mt9v111_data[sensorid].saturation = vc->value;
break;
case V4L2_CID_EXPOSURE:
pr_debug(" V4L2_CID_EXPOSURE\n");
- retval = mt9v111_set_ae_mode(vc->value);
- break;
- case V4L2_CID_AUTOGAIN:
- pr_debug(" V4L2_CID_AUTOGAIN\n");
+ retval = mt9v111_set_ae_mode(sensorid,vc->value);
+ mt9v111_data[sensorid].ae_mode = vc->value;
break;
case V4L2_CID_GAIN:
pr_debug(" V4L2_CID_GAIN\n");
- break;
- case V4L2_CID_HFLIP:
- pr_debug(" V4L2_CID_HFLIP\n");
- break;
- case V4L2_CID_VFLIP:
- pr_debug(" V4L2_CID_VFLIP\n");
+ mt9v111_set_digitalsharpness(sensorid,vc->value);
+ mt9v111_data[sensorid].gain = vc->value;
break;
default:
pr_debug(" Default case\n");
@@ -854,13 +1081,41 @@ static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
return retval;
}
+static void mt9v111_ifp_reset ( int sensorid )
+{
+ mt9v111_write_reg(sensorid,MT9V111S_ADDR_SPACE_SEL, 0x0001);
+ mt9v111_write_reg(sensorid,MT9V111I_SOFT_RESET, 0x0001);
+ msleep(100);
+ mt9v111_write_reg(sensorid,MT9V111I_SOFT_RESET, 0x0000);
+ msleep(100);
+}
+
+static void mt9v111_sensor_reset ( int sensorid )
+{
+ mt9v111_write_reg(sensorid,MT9V111S_ADDR_SPACE_SEL, 0x0004);
+ mt9v111_write_reg(sensorid,MT9V111S_RESET, 0x0001);
+ msleep(100);
+ mt9v111_write_reg(sensorid,MT9V111S_RESET, 0x0000);
+ msleep(100);
+}
+
/*!
* ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT
* @s: pointer to standard V4L2 device structure
*/
static int ioctl_init(struct v4l2_int_device *s)
{
- pr_debug("In mt9v111:ioctl_init\n");
+ int sensorid = 0;
+
+ sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name);
+ if( sensorid < 0 )
+ return 0;
+
+ pr_debug("In mt9v111:ioctl_init for sensor %d\n",sensorid);
+
+ mt9v111_sensor_reset(sensorid);
+ mt9v111_ifp_reset(sensorid);
+ mt9v111_sensor_lib_datasheet(sensorid,mt9v111_device.coreReg, mt9v111_device.ifpReg);
return 0;
}
@@ -873,19 +1128,146 @@ static int ioctl_init(struct v4l2_int_device *s)
*/
static int ioctl_dev_init(struct v4l2_int_device *s)
{
+ int sensorid = 0;
uint32_t clock_rate = MT9V111_MCLK;
+ sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name);
+ if( sensorid < 0 )
+ return 0;
+
pr_debug("In mt9v111:ioctl_dev_init\n");
- gpio_sensor_active();
+ set_mclk_rate(&clock_rate, 0); // Both sensors use mclk0 on Digi ccwmx51
+
+ mt9v111_sensor_reset(sensorid);
+ mt9v111_ifp_reset(sensorid);
+ mt9v111_sensor_lib_datasheet(sensorid,mt9v111_device.coreReg, mt9v111_device.ifpReg);
- set_mclk_rate(&clock_rate);
- mt9v111_rate_cal(&reset_frame_rate, clock_rate);
- mt9v111_sensor_lib(mt9v111_device.coreReg, mt9v111_device.ifpReg);
+ return 0;
+}
+
+/* list of image formats supported by sensor */
+static const struct v4l2_fmtdesc mt9v111_formats[] = {
+ {
+ .description = "RGB565",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ },
+ {
+ .description = "YUV422 UYVY",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+};
+
+#define MT9V111_NUM_CAPTURE_FORMATS ARRAY_SIZE(mt9v111_formats)
+
+static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_fmtdesc *fmt)
+{
+ int index = fmt->index;
+
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (index >= MT9V111_NUM_CAPTURE_FORMATS)
+ return -EINVAL;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ fmt->flags = mt9v111_formats[index].flags;
+ strlcpy(fmt->description, mt9v111_formats[index].description,
+ sizeof(fmt->description));
+ fmt->pixelformat = mt9v111_formats[index].pixelformat;
return 0;
}
+static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ unsigned short reg;
+ int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name);
+ struct sensor *sensor = s->priv;
+ /* s->priv points to mt9v111_data */
+
+ if( sensorid < 0 )
+ return -ENODEV;
+
+ /* Select IFP registers */
+ mt9v111_write_reg (sensorid,MT9V111S_ADDR_SPACE_SEL, 0x0001);
+
+ switch (f->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB565:
+ /*MT9V111I_OUTPUT_FORMAT_CTRL2*/
+ reg = mt9v111_read_reg (sensorid,MT9V111I_OUTPUT_FORMAT_CTRL2);
+ reg &= ~(0x3 << 6);
+ mt9v111_write_reg (sensorid,MT9V111I_OUTPUT_FORMAT_CTRL2, reg);
+
+ /* MT9V111I_FORMAT_CONTROL */
+ reg = mt9v111_read_reg(sensorid,MT9V111I_FORMAT_CONTROL);
+ reg |= 1 << 12;
+ mt9v111_write_reg(sensorid,MT9V111I_FORMAT_CONTROL, reg);
+ break;
+
+ case V4L2_PIX_FMT_YUV444:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_YUYV:
+ /* MT9V111I_FORMAT_CONTROL */
+ reg = mt9v111_read_reg(sensorid,MT9V111I_FORMAT_CONTROL);
+ reg &= ~(1 << 12);
+ mt9v111_write_reg(sensorid,MT9V111I_FORMAT_CONTROL, reg);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ sensor->pix.width = f->fmt.pix.width;
+ sensor->pix.height = f->fmt.pix.height;
+ sensor->pix.sizeimage = f->fmt.pix.sizeimage;
+ sensor->pix.pixelformat = f->fmt.pix.pixelformat;
+ return 0;
+}
+
+static int ioctl_try_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+{
+ int i;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ for( i=0 ; i < MT9V111_NUM_CAPTURE_FORMATS ; i++) {
+ if( f->fmt.pix.pixelformat == mt9v111_formats[i].pixelformat )
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ioctl_get_register(struct v4l2_int_device *s,struct v4l2_dbg_register * dreg)
+{
+ int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name);
+
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */ , true, true);
+ dreg->val = mt9v111_read_reg (sensorid,dreg->reg);
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */ , false, false);
+ return 0;
+}
+
+static int ioctl_set_register(struct v4l2_int_device *s,struct v4l2_dbg_register * dreg)
+{
+ int sensorid = mt9v111_id_from_name(((struct sensor *)s->priv)->v4l2_int_device->name);
+
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */ , true, true);
+ mt9v111_write_reg (sensorid,dreg->reg, dreg->val);
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, 0 /* cam->csi */ , false, false);
+ return 0;
+}
+#endif
+
/*!
* This structure defines all the ioctls for this module and links them to the
* enumeration.
@@ -910,16 +1292,23 @@ static struct v4l2_int_ioctl_desc mt9v111_ioctl_desc[] = {
/*!
* VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
*/
-/* {vidioc_int_enum_fmt_cap_num,
- (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap}, */
+ {vidioc_int_enum_fmt_cap_num,
+ (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap},
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ {vidioc_int_g_register_num,
+ (v4l2_int_ioctl_func *) ioctl_get_register},
+ {vidioc_int_s_register_num,
+ (v4l2_int_ioctl_func *) ioctl_set_register},
+#endif
/*!
* VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type.
* This ioctl is used to negotiate the image capture size and
* pixel format without actually making it take effect.
*/
-/* {vidioc_int_try_fmt_cap_num,
- (v4l2_int_ioctl_func *) ioctl_try_fmt_cap}, */
+ {vidioc_int_try_fmt_cap_num,
+ (v4l2_int_ioctl_func *) ioctl_try_fmt_cap},
{vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func *) ioctl_g_fmt_cap},
@@ -928,7 +1317,7 @@ static struct v4l2_int_ioctl_desc mt9v111_ioctl_desc[] = {
* format, returns error code if format not supported or HW can't be
* correctly configured.
*/
-/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap}, */
+ {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap},
{vidioc_int_g_parm_num, (v4l2_int_ioctl_func *) ioctl_g_parm},
{vidioc_int_s_parm_num, (v4l2_int_ioctl_func *) ioctl_s_parm},
@@ -937,20 +1326,56 @@ static struct v4l2_int_ioctl_desc mt9v111_ioctl_desc[] = {
{vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *) ioctl_s_ctrl},
};
-static struct v4l2_int_slave mt9v111_slave = {
- .ioctls = mt9v111_ioctl_desc,
- .num_ioctls = ARRAY_SIZE(mt9v111_ioctl_desc),
+static struct v4l2_int_slave mt9v111_slave[] = {
+ {
+ .ioctls = mt9v111_ioctl_desc,
+ .num_ioctls = ARRAY_SIZE(mt9v111_ioctl_desc),
+ .attach_to = "mxc_v4l2_cap_1",
+ },
+ {
+ .ioctls = mt9v111_ioctl_desc,
+ .num_ioctls = ARRAY_SIZE(mt9v111_ioctl_desc),
+ .attach_to = "mxc_v4l2_cap_2",
+ },
};
-static struct v4l2_int_device mt9v111_int_device = {
- .module = THIS_MODULE,
- .name = "mt9v111",
- .type = v4l2_int_type_slave,
- .u = {
- .slave = &mt9v111_slave,
+static struct v4l2_int_device mt9v111_int_device [] = {
+ {
+ .module = THIS_MODULE,
+ .type = v4l2_int_type_slave,
+ .u = {
+ .slave = &mt9v111_slave[0],
+ },
+ },
+ {
+ .module = THIS_MODULE,
+ .type = v4l2_int_type_slave,
+ .u = {
+ .slave = &mt9v111_slave[1],
+ },
},
};
+static int mt9v111_read_id( int sensoridx )
+{
+ int sensorid = 0;
+ int ret = 0;
+
+ mt9v111_write_reg (sensoridx,MT9V111S_ADDR_SPACE_SEL, 0x0004);
+
+ sensorid = mt9v111_read_reg (sensoridx,MT9V111S_CHIP_VERSION);
+ if( sensorid == 0x823a )
+ {
+ printk(KERN_INFO" MT9V111 ID %x\n",sensorid);
+ }
+ else
+ {
+ printk(KERN_ERR" MT9V111 Could not detect sensor (read %x)\n",sensorid);
+ ret = -ENODEV;
+ }
+ return ret;
+}
+
/*!
* mt9v111 I2C probe function
* Function set in i2c_driver struct.
@@ -962,32 +1387,56 @@ static int mt9v111_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int retval;
+ int sensorid;
pr_debug("In mt9v111_probe device id is %s\n", id->name);
+ sensorid = mt9v111_id_from_name(id->name);
+
+ if( sensorid < 0 )
+ return -ENODEV;
+
/* Set initial values for the sensor struct. */
- memset(&mt9v111_data, 0, sizeof(mt9v111_data));
- mt9v111_data.i2c_client = client;
+ memset(&mt9v111_data[sensorid], 0, sizeof(struct sensor));
+ mt9v111_data[sensorid].i2c_client = client;
pr_debug(" client name is %s\n", client->name);
- mt9v111_data.pix.pixelformat = V4L2_PIX_FMT_UYVY;
- mt9v111_data.pix.width = MT9V111_MAX_WIDTH;
- mt9v111_data.pix.height = MT9V111_MAX_HEIGHT;
- mt9v111_data.streamcap.capability = 0; /* No higher resolution or frame
- * frame rate changes supported.
- */
- mt9v111_data.streamcap.timeperframe.denominator = MT9V111_FRAME_RATE;
- mt9v111_data.streamcap.timeperframe.numerator = 1;
+ mt9v111_data[sensorid].pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ mt9v111_data[sensorid].pix.width = MT9V111_MAX_WIDTH;
+ mt9v111_data[sensorid].pix.height = MT9V111_MAX_HEIGHT;
+ mt9v111_data[sensorid].streamcap.capability = 0; /* No higher resolution or frame
+ * frame rate changes supported.*/
+ mt9v111_data[sensorid].streamcap.timeperframe.denominator = MT9V111_FRAME_RATE;
+ mt9v111_data[sensorid].streamcap.timeperframe.numerator = 1;
+
+ strcpy(mt9v111_int_device[sensorid].name,id->name);
+ pr_debug(" video device name is %s\n", mt9v111_data[sensorid].v4l2_int_device->name);
+ mt9v111_data[sensorid].v4l2_int_device = &mt9v111_int_device[sensorid];
+ mt9v111_int_device[sensorid].priv = &mt9v111_data[sensorid];
+
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, sensorid , true, true);
+
+ if( mt9v111_read_id(sensorid) != 0) {
+ printk(KERN_ERR"mt9v111_probe: No sensor found\n");
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, sensorid , false, false);
+ return -ENXIO;
+ }
- mt9v111_int_device.priv = &mt9v111_data;
+#ifdef MT9V111_DEBUG
+ mt9v111_test_pattern(1);
+#endif
+
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, sensorid , false, false);
pr_debug(" type is %d (expect %d)\n",
- mt9v111_int_device.type, v4l2_int_type_slave);
+ mt9v111_int_device[sensorid].type, v4l2_int_type_slave);
pr_debug(" num ioctls is %d\n",
- mt9v111_int_device.u.slave->num_ioctls);
+ mt9v111_int_device[sensorid].u.slave->num_ioctls);
/* This function attaches this structure to the /dev/video0 device.
* The pointer in priv points to the mt9v111_data structure here.*/
- retval = v4l2_int_device_register(&mt9v111_int_device);
+ retval = v4l2_int_device_register(&mt9v111_int_device[sensorid]);
+ if( retval == 0 )
+ mt9v111_data[sensorid].used = 1;
return retval;
}
@@ -998,9 +1447,14 @@ static int mt9v111_probe(struct i2c_client *client,
*/
static int mt9v111_remove(struct i2c_client *client)
{
+ int i;
+
pr_debug("In mt9v111_remove\n");
- v4l2_int_device_unregister(&mt9v111_int_device);
+ for ( i=0 ; i < ARRAY_SIZE(mt9v111_int_device) ; i++ ) {
+ if( mt9v111_data[i].used )
+ v4l2_int_device_unregister(&mt9v111_int_device[i]);
+ }
return 0;
}
@@ -1033,13 +1487,13 @@ static __init int mt9v111_init(void)
memset(mt9v111_device.ifpReg, 0, sizeof(mt9v111_IFPReg));
/* Set contents of the just created structures. */
- mt9v111_config();
+ mt9v111_config_datasheet();
/* Tells the i2c driver what functions to call for this driver. */
err = i2c_add_driver(&mt9v111_i2c_driver);
if (err != 0)
pr_err("%s:driver registration failed, error=%d \n",
- __func__, err);
+ __func__, err);
return err;
}
@@ -1055,7 +1509,6 @@ static void __exit mt9v111_clean(void)
pr_debug("In mt9v111_clean()\n");
i2c_del_driver(&mt9v111_i2c_driver);
- gpio_sensor_inactive();
if (mt9v111_device.coreReg) {
kfree(mt9v111_device.coreReg);
diff --git a/drivers/media/video/mxc/capture/mt9v111.h b/drivers/media/video/mxc/capture/mt9v111.h
index cf38cec4757c..ba91a722a076 100644
--- a/drivers/media/video/mxc/capture/mt9v111.h
+++ b/drivers/media/video/mxc/capture/mt9v111.h
@@ -111,11 +111,14 @@
#define MT9V111I_GAMMA_KNEE_Y90 0x57
#define MT9V111I_GAMMA_VALUE_Y0 0x58
#define MT9V111I_SHUTTER_60 0x59
+#define MT9V111I_AUTO_EXPOSURE_17 0x5A
#define MT9V111I_SEARCH_FLICK_60 0x5c
+#define MT9V111I_RESERVED93 0x5d
#define MT9V111I_RATIO_IMAGE_GAIN_BASE 0x5e
#define MT9V111I_RATIO_IMAGE_GAIN_DELTA 0x5f
#define MT9V111I_SIGN_VALUE_REG5F 0x60
#define MT9V111I_AE_GAIN 0x62
+#define MT9V111I_RESERVED100 0x64
#define MT9V111I_MAX_GAIN_AE 0x67
#define MT9V111I_LENS_CORRECT_CTRL 0x80
#define MT9V111I_SHADING_PARAMETER1 0x81
@@ -173,6 +176,7 @@
#define MT9V111S_ROW_START_IN_ZOOM 0x13
#define MT9V111S_DIGITAL_ZOOM 0x1e
#define MT9V111S_READ_MODE 0x20
+#define MT9V111S_RESERVED33 0x21
#define MT9V111S_DAC_CTRL 0x27
#define MT9V111S_GREEN1_GAIN 0x2b
#define MT9V111S_BLUE_GAIN 0x2c
@@ -278,6 +282,7 @@ typedef struct {
u32 rowNoiseControl;
u32 darkTargetwNC;
u32 testData; /*!< test mode */
+ u32 reserved33;
u32 globalGain;
u32 chipVersion;
u32 darkTargetwoNC;
@@ -375,11 +380,14 @@ typedef struct {
u32 gammaKneeY90; /*!< Gamma knee points Y9 and Y10 */
u32 gammaKneeY0; /*!< Gamma knee point Y0 */
u32 shutter_width_60;
+ u32 auto_exposure_17;
u32 search_flicker_60;
+ u32 reserved93;
u32 ratioImageGainBase;
u32 ratioImageGainDelta;
u32 signValueReg5F;
u32 aeGain;
+ u32 reserved100;
u32 maxGainAE;
u32 lensCorrectCtrl;
u32 shadingParameter1; /*!< Shade Parameters */
diff --git a/drivers/media/video/mxc/capture/mx27_prpsw.c b/drivers/media/video/mxc/capture/mx27_prpsw.c
index ce7db16913ec..eca200a580f2 100644
--- a/drivers/media/video/mxc/capture/mx27_prpsw.c
+++ b/drivers/media/video/mxc/capture/mx27_prpsw.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -702,7 +702,7 @@ static int prp_still_start(void *private)
cam_data *cam = (cam_data *) private;
g_still_on = 1;
- g_prp_cfg.ch2_ptr = (unsigned int)cam->still_buf;
+ g_prp_cfg.ch2_ptr = (unsigned int)cam->still_buf[0];
g_prp_cfg.ch2_ptr2 = 0;
if (prp_v4l2_cfg(&g_prp_cfg, cam))
diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.c b/drivers/media/video/mxc/capture/mxc_v4l2_capture.c
index 30ad533b0ebd..be9a988aff2f 100644
--- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.c
+++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.c
@@ -18,6 +18,8 @@
*
* @ingroup MXC_V4L2_CAPTURE
*/
+
+
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -37,9 +39,9 @@
#include <media/v4l2-int-device.h>
#include "mxc_v4l2_capture.h"
#include "ipu_prp_sw.h"
+#include "asm/delay.h"
static int video_nr = -1;
-static cam_data *g_cam;
/*! This data is used for the output to the display. */
#define MXC_V4L2_CAPTURE_NUM_OUTPUTS 3
@@ -74,21 +76,23 @@ static struct v4l2_output mxc_capture_outputs[MXC_V4L2_CAPTURE_NUM_OUTPUTS] = {
static struct v4l2_input mxc_capture_inputs[MXC_V4L2_CAPTURE_NUM_INPUTS] = {
{
.index = 0,
- .name = "CSI IC MEM",
+ .name = "CSI MEM",
.type = V4L2_INPUT_TYPE_CAMERA,
.audioset = 0,
.tuner = 0,
.std = V4L2_STD_UNKNOWN,
- .status = 0,
+ .status = V4L2_IN_ST_NO_POWER,
},
{
.index = 1,
+// AG: CSI IC MEM works but has problems
+// .name = "CSI IC MEM",
.name = "CSI MEM",
.type = V4L2_INPUT_TYPE_CAMERA,
.audioset = 0,
.tuner = 0,
.std = V4L2_STD_UNKNOWN,
- .status = V4L2_IN_ST_NO_POWER,
+ .status = 0,
},
};
@@ -118,6 +122,7 @@ typedef struct {
u16 active_left; /*!< Active left. */
} video_fmt_t;
+#if 0
/*!
* Description of video formats supported.
*
@@ -128,37 +133,39 @@ static video_fmt_t video_fmts[] = {
{ /*! NTSC */
.v4l2_id = V4L2_STD_NTSC,
.name = "NTSC",
- .raw_width = 720 - 1, /* SENS_FRM_WIDTH */
- .raw_height = 288 - 1, /* SENS_FRM_HEIGHT */
- .active_width = 720, /* ACT_FRM_WIDTH plus 1 */
- .active_height = (480 / 2), /* ACT_FRM_HEIGHT plus 1 */
- .active_top = 12,
+ .raw_width = 720, /* SENS_FRM_WIDTH */
+ .raw_height = 525, /* SENS_FRM_HEIGHT */
+ .active_width = 720, /* ACT_FRM_WIDTH */
+ .active_height = 240, /* ACT_FRM_HEIGHT */
+ .active_top = 0,
.active_left = 0,
},
{ /*! (B, G, H, I, N) PAL */
.v4l2_id = V4L2_STD_PAL,
.name = "PAL",
- .raw_width = 720 - 1,
- .raw_height = (576 / 2) + 24 * 2 - 1,
+ .raw_width = 720,
+ .raw_height = 625,
.active_width = 720,
- .active_height = (576 / 2),
+ .active_height = 288,
.active_top = 0,
.active_left = 0,
},
{ /*! Unlocked standard */
.v4l2_id = V4L2_STD_ALL,
.name = "Autodetect",
- .raw_width = 720 - 1,
- .raw_height = (576 / 2) + 24 * 2 - 1,
+ .raw_width = 720,
+ .raw_height = 625,
.active_width = 720,
- .active_height = (576 / 2),
+ .active_height = 288,
.active_top = 0,
.active_left = 0,
},
};
+
/*!* Standard index of TV. */
static video_fmt_idx video_index = TV_NOT_LOCKED;
+#endif
static int mxc_v4l2_master_attach(struct v4l2_int_device *slave);
static void mxc_v4l2_master_detach(struct v4l2_int_device *slave);
@@ -172,15 +179,27 @@ static struct v4l2_int_master mxc_v4l2_master = {
.detach = mxc_v4l2_master_detach,
};
-static struct v4l2_int_device mxc_v4l2_int_device = {
+static struct v4l2_int_device mxc_v4l2_int_device [] = {
+ {
+ .module = THIS_MODULE,
+ .name = "mxc_v4l2_cap_1",
+ .type = v4l2_int_type_master,
+ .u = {
+ .master = &mxc_v4l2_master,
+ },
+ },
+ {
.module = THIS_MODULE,
- .name = "mxc_v4l2_cap",
+ .name = "mxc_v4l2_cap_2",
.type = v4l2_int_type_master,
.u = {
.master = &mxc_v4l2_master,
},
+ },
};
+static cam_data *g_cam[ARRAY_SIZE(mxc_v4l2_int_device)];
+
/***************************************************************************
* Functions for handling Frame buffers.
**************************************************************************/
@@ -260,6 +279,7 @@ static int mxc_allocate_frame_buf(cam_data *cam, int count)
static void mxc_free_frames(cam_data *cam)
{
int i;
+ unsigned long lock_flags;
pr_debug("In MVC:mxc_free_frames\n");
@@ -269,9 +289,11 @@ static void mxc_free_frames(cam_data *cam)
cam->enc_counter = 0;
cam->skip_frame = 0;
+ spin_lock_irqsave(&cam->dqueue_int_lock, lock_flags);
INIT_LIST_HEAD(&cam->ready_q);
INIT_LIST_HEAD(&cam->working_q);
INIT_LIST_HEAD(&cam->done_q);
+ spin_unlock_irqrestore(&cam->dqueue_int_lock, lock_flags);
}
/*!
@@ -331,8 +353,7 @@ static int mxc_streamon(cam_data *cam)
{
struct mxc_v4l_frame *frame;
int err = 0;
-
- pr_debug("In MVC:mxc_streamon\n");
+ unsigned long lock_flags;
if (NULL == cam) {
pr_err("ERROR! cam parameter is NULL\n");
@@ -363,23 +384,27 @@ static int mxc_streamon(cam_data *cam)
}
}
+ spin_lock_irqsave(&cam->queue_int_lock, lock_flags);
cam->ping_pong_csi = 0;
if (cam->enc_update_eba) {
- frame =
- list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue);
- list_del(cam->ready_q.next);
- list_add_tail(&frame->queue, &cam->working_q);
- err = cam->enc_update_eba(frame->buffer.m.offset,
- &cam->ping_pong_csi);
frame =
list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue);
list_del(cam->ready_q.next);
list_add_tail(&frame->queue, &cam->working_q);
- err |= cam->enc_update_eba(frame->buffer.m.offset,
- &cam->ping_pong_csi);
+ err = cam->enc_update_eba(cam->csi,frame->buffer.m.offset,
+ &cam->ping_pong_csi);
+ if (!list_empty(&cam->ready_q)) {
+ frame =
+ list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue);
+ list_del(cam->ready_q.next);
+ list_add_tail(&frame->queue, &cam->working_q);
+ err |= cam->enc_update_eba(cam->csi,frame->buffer.m.offset,
+ &cam->ping_pong_csi);
+ }
+ cam->capture_on = true;
} else {
- return -EINVAL;
+ err = -EINVAL;
}
if (cam->overlay_on == true)
@@ -387,11 +412,9 @@ static int mxc_streamon(cam_data *cam)
if (cam->enc_enable_csi) {
err = cam->enc_enable_csi(cam);
- if (err != 0)
- return err;
}
- cam->capture_on = true;
+ spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags);
return err;
}
@@ -543,8 +566,6 @@ static int start_preview(cam_data *cam)
{
int err = 0;
- pr_debug("MVC: start_preview\n");
-
#if defined(CONFIG_MXC_IPU_PRP_VF_SDC) || defined(CONFIG_MXC_IPU_PRP_VF_SDC_MODULE)
pr_debug(" This is an SDC display\n");
if (cam->output == 0 || cam->output == 2) {
@@ -602,8 +623,6 @@ static int stop_preview(cam_data *cam)
{
int err = 0;
- pr_debug("MVC: stop preview\n");
-
#if defined(CONFIG_MXC_IPU_PRP_VF_ADC) || defined(CONFIG_MXC_IPU_PRP_VF_ADC_MODULE)
if (cam->output == 1) {
err = prp_vf_adc_deselect(cam);
@@ -674,6 +693,29 @@ static int mxc_v4l2_g_fmt(cam_data *cam, struct v4l2_format *f)
__func__,
cam->crop_current.width, cam->crop_current.height);
+ retval = vidioc_int_g_fmt_cap(cam->sensor,f);
+ return retval;
+}
+
+/*!
+ * V4L2 - mxc_v4l2_enum_fmt function
+ *
+ * @param cam structure cam_data *
+ *
+ * @param f structure v4l2_fmtdesc *
+ *
+ * @return status 0 success, EINVAL failed
+ */
+static int mxc_v4l2_enum_fmt(cam_data *cam, struct v4l2_fmtdesc *f)
+{
+ int retval = 0;
+
+ pr_debug("In MVC: mxc_v4l2_enum_fmt\n");
+
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true);
+ retval = vidioc_int_enum_fmt_cap(cam->sensor,f);
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false);
+
return retval;
}
@@ -709,10 +751,14 @@ static int mxc_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f)
* for CSI MEM input mode.
*/
if (strcmp(mxc_capture_inputs[cam->current_input].name,
- "CSI MEM") == 0) {
+ "CSI MEM") == 0 || strcmp(mxc_capture_inputs[cam->current_input].name,
+ "CSI IC MEM") == 0) {
f->fmt.pix.width = cam->crop_current.width;
f->fmt.pix.height = cam->crop_current.height;
}
+ else {
+ printk("Error no match %s\n",mxc_capture_inputs[cam->current_input].name);
+ }
if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
height = &f->fmt.pix.width;
@@ -811,6 +857,13 @@ static int mxc_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f)
break;
}
}
+
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi,
+ true, true);
+ vidioc_int_s_fmt_cap(cam->sensor, f);
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi,
+ false, false);
+
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
pr_debug(" type=V4L2_BUF_TYPE_VIDEO_OVERLAY\n");
@@ -1057,63 +1110,10 @@ static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c)
return ret;
}
-/*!
- * V4L2 - mxc_v4l2_s_param function
- * Allows setting of capturemode and frame rate.
- *
- * @param cam structure cam_data *
- * @param parm structure v4l2_streamparm *
- *
- * @return status 0 success, EINVAL failed
- */
-static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm)
-{
- struct v4l2_ifparm ifparm;
+static int mxc_v4l2_init_csi( cam_data *cam ) {
struct v4l2_format cam_fmt;
- struct v4l2_streamparm currentparm;
ipu_csi_signal_cfg_t csi_param;
- int err = 0;
-
- pr_debug("In mxc_v4l2_s_param\n");
-
- if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- pr_err(KERN_ERR "mxc_v4l2_s_param invalid type\n");
- return -EINVAL;
- }
-
- /* Stop the viewfinder */
- if (cam->overlay_on == true) {
- stop_preview(cam);
- }
-
- currentparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- /* First check that this device can support the changes requested. */
- err = vidioc_int_g_parm(cam->sensor, &currentparm);
- if (err) {
- pr_err("%s: vidioc_int_g_parm returned an error %d\n",
- __func__, err);
- goto exit;
- }
-
- pr_debug(" Current capabilities are %x\n",
- currentparm.parm.capture.capability);
- pr_debug(" Current capturemode is %d change to %d\n",
- currentparm.parm.capture.capturemode,
- parm->parm.capture.capturemode);
- pr_debug(" Current framerate is %d change to %d\n",
- currentparm.parm.capture.timeperframe.denominator,
- parm->parm.capture.timeperframe.denominator);
-
- /* This will change any camera settings needed. */
- ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true);
- err = vidioc_int_s_parm(cam->sensor, parm);
- ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false);
- if (err) {
- pr_err("%s: vidioc_int_s_parm returned an error %d\n",
- __func__, err);
- goto exit;
- }
+ struct v4l2_ifparm ifparm;
/* If resolution changed, need to re-program the CSI */
/* Get new values. */
@@ -1131,13 +1131,13 @@ static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm)
csi_param.force_eof = 0;
csi_param.data_en_pol = 0;
csi_param.data_fmt = 0;
- csi_param.csi = 0;
+ csi_param.csi = cam->csi;
csi_param.mclk = 0;
/* This may not work on other platforms. Check when adding a new one.*/
pr_debug(" clock_curr=mclk=%d\n", ifparm.u.bt656.clock_curr);
if (ifparm.u.bt656.clock_curr == 0) {
- csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
+ csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
} else {
csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
}
@@ -1189,7 +1189,63 @@ static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm)
ipu_csi_init_interface(cam->crop_bounds.width,
cam->crop_bounds.height,
cam_fmt.fmt.pix.pixelformat, csi_param);
+ return 0;
+}
+/*!
+ * V4L2 - mxc_v4l2_s_param function
+ * Allows setting of capturemode and frame rate.
+ *
+ * @param cam structure cam_data *
+ * @param parm structure v4l2_streamparm *
+ *
+ * @return status 0 success, EINVAL failed
+ */
+static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm)
+{
+ struct v4l2_streamparm currentparm;
+ int err = 0;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ pr_err(KERN_ERR "mxc_v4l2_s_param invalid type\n");
+ return -EINVAL;
+ }
+
+ /* Stop the viewfinder */
+ if (cam->overlay_on == true) {
+ stop_preview(cam);
+ }
+
+ currentparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ /* First check that this device can support the changes requested. */
+ err = vidioc_int_g_parm(cam->sensor, &currentparm);
+ if (err) {
+ pr_err("%s: vidioc_int_g_parm returned an error %d\n",
+ __func__, err);
+ goto exit;
+ }
+
+ pr_debug(" Current capabilities are %x\n",
+ currentparm.parm.capture.capability);
+ pr_debug(" Current capturemode is %d change to %d\n",
+ currentparm.parm.capture.capturemode,
+ parm->parm.capture.capturemode);
+ pr_debug(" Current framerate is %d change to %d\n",
+ currentparm.parm.capture.timeperframe.denominator,
+ parm->parm.capture.timeperframe.denominator);
+
+ /* This will change any camera settings needed. */
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true);
+ err = vidioc_int_s_parm(cam->sensor, parm);
+ ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false);
+ if (err) {
+ pr_err("%s: vidioc_int_s_parm returned an error %d\n",
+ __func__, err);
+ goto exit;
+ }
+
+ err = mxc_v4l2_init_csi(cam);
exit:
if (cam->overlay_on == true)
@@ -1198,6 +1254,7 @@ exit:
return err;
}
+#if 0
/*!
* V4L2 - mxc_v4l2_s_std function
*
@@ -1287,6 +1344,7 @@ static int mxc_v4l2_g_std(cam_data *cam, v4l2_std_id *e)
return 0;
}
+#endif
/*!
* Dequeue one V4L capture buffer
@@ -1372,6 +1430,11 @@ static int mxc_v4l_open(struct file *file)
return -EBADF;
}
+ if(!cam->sensor) {
+ pr_err("ERROR: v4l2 capture: Unattached sensor!\n");
+ return -EBADF;
+ }
+
down(&cam->busy_lock);
err = 0;
if (signal_pending(current))
@@ -1411,12 +1474,9 @@ static int mxc_v4l_open(struct file *file)
csi_param.force_eof = 0;
csi_param.data_en_pol = 0;
csi_param.mclk = ifparm.u.bt656.clock_curr;
-
+ csi_param.ext_vsync = ifparm.u.bt656.bt_sync_correct;
csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv;
- /* Once we handle multiple inputs this will need to change. */
- csi_param.csi = 0;
-
if (ifparm.u.bt656.mode
== V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT)
csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
@@ -1464,11 +1524,13 @@ static int mxc_v4l_open(struct file *file)
__func__,
cam->crop_current.width, cam->crop_current.height);
+ udelay(100);
+
csi_param.data_fmt = cam_fmt.fmt.pix.pixelformat;
pr_debug("On Open: Input to ipu size is %d x %d\n",
cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height);
ipu_csi_set_window_size(cam->crop_current.width,
- cam->crop_current.width,
+ cam->crop_current.height,
cam->csi);
ipu_csi_set_window_pos(cam->crop_current.left,
cam->crop_current.top,
@@ -1478,12 +1540,16 @@ static int mxc_v4l_open(struct file *file)
cam_fmt.fmt.pix.pixelformat,
csi_param);
+ udelay(100);
+
ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi,
true, true);
vidioc_int_init(cam->sensor);
ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi,
false, false);
+
+ udelay(100);
}
file->private_data = dev;
@@ -1519,7 +1585,7 @@ static int mxc_v4l_close(struct file *file)
err = stop_preview(cam);
cam->overlay_on = false;
}
- if (cam->capture_pid == current->pid) {
+ if (cam->capture_pid == current->tgid) {
err |= mxc_streamoff(cam);
wake_up_interruptible(&cam->enc_queue);
}
@@ -1570,7 +1636,7 @@ static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count,
loff_t *ppos)
{
int err = 0;
- u8 *v_address;
+ u8 *v_address[2];
struct video_device *dev = video_devdata(file);
cam_data *cam = video_get_drvdata(dev);
@@ -1581,11 +1647,17 @@ static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count,
if (cam->overlay_on == true)
stop_preview(cam);
- v_address = dma_alloc_coherent(0,
+ v_address[0] = dma_alloc_coherent(0,
PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
- &cam->still_buf, GFP_DMA | GFP_KERNEL);
+ &cam->still_buf[0],
+ GFP_DMA | GFP_KERNEL);
+
+ v_address[1] = dma_alloc_coherent(0,
+ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+ &cam->still_buf[1],
+ GFP_DMA | GFP_KERNEL);
- if (!v_address) {
+ if (!v_address[0] || !v_address[1]) {
err = -ENOBUFS;
goto exit0;
}
@@ -1593,14 +1665,14 @@ static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count,
err = prp_still_select(cam);
if (err != 0) {
err = -EIO;
- goto exit1;
+ goto exit0;
}
cam->still_counter = 0;
err = cam->csi_start(cam);
if (err != 0) {
err = -EIO;
- goto exit2;
+ goto exit1;
}
if (!wait_event_interruptible_timeout(cam->still_queue,
@@ -1609,19 +1681,23 @@ static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count,
pr_err("ERROR: v4l2 capture: mxc_v4l_read timeout counter %x\n",
cam->still_counter);
err = -ETIME;
- goto exit2;
+ goto exit1;
}
- err = copy_to_user(buf, v_address, cam->v2f.fmt.pix.sizeimage);
-
- exit2:
- prp_still_deselect(cam);
+ err = copy_to_user(buf, v_address[1], cam->v2f.fmt.pix.sizeimage);
exit1:
- dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address,
- cam->still_buf);
- cam->still_buf = 0;
+ prp_still_deselect(cam);
exit0:
+ if (v_address[0] != 0)
+ dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address[0],
+ cam->still_buf[0]);
+ if (v_address[1] != 0)
+ dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address[1],
+ cam->still_buf[1]);
+
+ cam->still_buf[0] = cam->still_buf[1] = 0;
+
if (cam->overlay_on == true) {
start_preview(cam);
}
@@ -1661,6 +1737,21 @@ static long mxc_v4l_do_ioctl(struct file *file,
return -EBUSY;
switch (ioctlnr) {
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_DBG_S_REGISTER: {
+ struct v4l2_dbg_register * dreg = arg;
+ vidioc_int_s_register(cam->sensor,dreg);
+ break;
+ }
+
+ case VIDIOC_DBG_G_REGISTER: {
+ struct v4l2_dbg_register * dreg = arg;
+ vidioc_int_g_register(cam->sensor,dreg);
+ break;
+ }
+#endif
+
/*!
* V4l2 VIDIOC_QUERYCAP ioctl
*/
@@ -1695,6 +1786,14 @@ static long mxc_v4l_do_ioctl(struct file *file,
struct v4l2_format *sf = arg;
pr_debug(" case VIDIOC_S_FMT\n");
retval = mxc_v4l2_s_fmt(cam, sf);
+ mxc_v4l2_init_csi(cam);
+ break;
+ }
+
+ case VIDIOC_ENUM_FMT: {
+ struct v4l2_fmtdesc *fd = arg;
+ pr_debug(" case VIDIOC_ENUM_FMT\n");
+ retval = mxc_v4l2_enum_fmt(cam, fd);
break;
}
@@ -1775,9 +1874,8 @@ static long mxc_v4l_do_ioctl(struct file *file,
if (cam->skip_frame > 0) {
list_add_tail(&cam->frame[index].queue,
&cam->working_q);
-
retval =
- cam->enc_update_eba(cam->
+ cam->enc_update_eba(cam->csi,cam->
frame[index].
buffer.m.offset,
&cam->
@@ -1999,28 +2097,6 @@ static long mxc_v4l_do_ioctl(struct file *file,
break;
}
- /* linux v4l2 bug, kernel c0485619 user c0405619 */
- case VIDIOC_ENUMSTD: {
- struct v4l2_standard *e = arg;
- pr_debug(" case VIDIOC_ENUMSTD\n");
- *e = cam->standard;
- break;
- }
-
- case VIDIOC_G_STD: {
- v4l2_std_id *e = arg;
- pr_debug(" case VIDIOC_G_STD\n");
- retval = mxc_v4l2_g_std(cam, e);
- break;
- }
-
- case VIDIOC_S_STD: {
- v4l2_std_id *e = arg;
- pr_debug(" case VIDIOC_S_STD\n");
- retval = mxc_v4l2_s_std(cam, *e);
-
- break;
- }
case VIDIOC_ENUMOUTPUT: {
struct v4l2_output *output = arg;
@@ -2109,8 +2185,13 @@ static long mxc_v4l_do_ioctl(struct file *file,
break;
}
- case VIDIOC_ENUM_FMT:
- case VIDIOC_TRY_FMT:
+ case VIDIOC_TRY_FMT: {
+ struct v4l2_format * f = arg;
+ pr_debug(" case VIDIOC_TRY_FMT\n");
+ retval = vidioc_int_try_fmt_cap(cam->sensor,f);
+ break;
+ }
+
case VIDIOC_QUERYCTRL:
case VIDIOC_G_TUNER:
case VIDIOC_S_TUNER:
@@ -2163,7 +2244,7 @@ static int mxc_mmap(struct file *file, struct vm_area_struct *vma)
return -EINTR;
size = vma->vm_end - vma->vm_start;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
if (remap_pfn_range(vma, vma->vm_start,
vma->vm_pgoff, size, vma->vm_page_prot)) {
@@ -2236,12 +2317,21 @@ static void camera_platform_release(struct device *device)
}
/*! Device Definition for Mt9v111 devices */
-static struct platform_device mxc_v4l2_devices = {
- .name = "mxc_v4l2",
- .dev = {
- .release = camera_platform_release,
- },
- .id = 0,
+static struct platform_device mxc_v4l2_devices[] = {
+ {
+ .name = "mxc_v4l2_1",
+ .dev = {
+ .release = camera_platform_release,
+ },
+ .id = 0,
+ },
+ {
+ .name = "mxc_v4l2_2",
+ .dev = {
+ .release = camera_platform_release,
+ },
+ .id = 1,
+ }
};
/*!
@@ -2302,7 +2392,7 @@ static void camera_callback(u32 mask, void *dev)
struct mxc_v4l_frame,
queue);
- if (cam->enc_update_eba(
+ if (cam->enc_update_eba(cam->csi,
ready_frame->buffer.m.offset,
&cam->ping_pong_csi) == 0) {
list_del(cam->ready_q.next);
@@ -2354,7 +2444,7 @@ static void camera_callback(u32 mask, void *dev)
ready_frame = list_entry(cam->ready_q.next,
struct mxc_v4l_frame,
queue);
- if (cam->enc_update_eba(ready_frame->buffer.m.offset,
+ if (cam->enc_update_eba(cam->csi,ready_frame->buffer.m.offset,
&cam->ping_pong_csi) == 0) {
list_del(cam->ready_q.next);
list_add_tail(&ready_frame->queue,
@@ -2362,7 +2452,7 @@ static void camera_callback(u32 mask, void *dev)
} else
return;
} else {
- if (cam->enc_update_eba(
+ if (cam->enc_update_eba(cam->csi,
cam->dummy_frame.buffer.m.offset,
&cam->ping_pong_csi) == -EACCES)
return;
@@ -2379,13 +2469,15 @@ static void camera_callback(u32 mask, void *dev)
*
* @return status 0 Success
*/
-static void init_camera_struct(cam_data *cam)
+static void init_camera_struct(cam_data *cam,unsigned int csi)
{
- pr_debug("In MVC: init_camera_struct\n");
+ pr_debug("In MVC: init_camera_struct for csi %d\n",csi);
/* Default everything to 0 */
memset(cam, 0, sizeof(cam_data));
+ cam->csi = csi;
+
init_MUTEX(&cam->param_lock);
init_MUTEX(&cam->busy_lock);
@@ -2396,7 +2488,7 @@ static void init_camera_struct(cam_data *cam)
*(cam->video_dev) = mxc_v4l_template;
video_set_drvdata(cam->video_dev, cam);
- dev_set_drvdata(&mxc_v4l2_devices.dev, (void *)cam);
+ dev_set_drvdata(&mxc_v4l2_devices[csi].dev, (void *)cam);
cam->video_dev->minor = -1;
init_waitqueue_head(&cam->enc_queue);
@@ -2428,6 +2520,8 @@ static void init_camera_struct(cam_data *cam)
cam->skip_frame = 0;
cam->v4l2_fb.flags = V4L2_FBUF_FLAG_OVERLAY;
+ cam->current_input = cam->csi;
+
cam->v2f.fmt.pix.sizeimage = 352 * 288 * 3 / 2;
cam->v2f.fmt.pix.bytesperline = 288 * 3 / 2;
cam->v2f.fmt.pix.width = 288;
@@ -2438,9 +2532,6 @@ static void init_camera_struct(cam_data *cam)
cam->win.w.left = 0;
cam->win.w.top = 0;
- cam->csi = 0; /* Need to determine how to set this correctly with
- * multiple video input devices. */
-
cam->enc_callback = camera_callback;
init_waitqueue_head(&cam->power_queue);
spin_lock_init(&cam->queue_int_lock);
@@ -2460,11 +2551,12 @@ static u8 camera_power(cam_data *cam, bool cameraOn)
{
pr_debug("In MVC:camera_power on=%d\n", cameraOn);
+ if( !cam->open_count )
+ return 0;
+
if (cameraOn == true) {
- ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true);
vidioc_int_s_power(cam->sensor, 1);
} else {
- ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false);
vidioc_int_s_power(cam->sensor, 0);
}
return 0;
@@ -2491,15 +2583,15 @@ static int mxc_v4l2_suspend(struct platform_device *pdev, pm_message_t state)
return -1;
}
+ if (!cam->open_count) {
+ return 0;
+ }
+
cam->low_power = true;
if (cam->overlay_on == true)
stop_preview(cam);
- if ((cam->capture_on == true) && cam->enc_disable) {
- cam->enc_disable(cam);
- }
camera_power(cam, false);
-
return 0;
}
@@ -2522,14 +2614,19 @@ static int mxc_v4l2_resume(struct platform_device *pdev)
return -1;
}
+ if( !cam->open_count )
+ return 0;
+
cam->low_power = false;
wake_up_interruptible(&cam->power_queue);
+
camera_power(cam, true);
if (cam->overlay_on == true)
start_preview(cam);
+
if (cam->capture_on == true)
- mxc_streamon(cam);
+ mxc_streamon(cam);
return 0;
}
@@ -2537,15 +2634,27 @@ static int mxc_v4l2_resume(struct platform_device *pdev)
/*!
* This structure contains pointers to the power management callback functions.
*/
-static struct platform_driver mxc_v4l2_driver = {
- .driver = {
- .name = "mxc_v4l2",
- },
- .probe = NULL,
- .remove = NULL,
- .suspend = mxc_v4l2_suspend,
- .resume = mxc_v4l2_resume,
- .shutdown = NULL,
+static struct platform_driver mxc_v4l2_driver[] = {
+ {
+ .driver = {
+ .name = "mxc_v4l2_1",
+ },
+ .probe = NULL,
+ .remove = NULL,
+ .suspend = mxc_v4l2_suspend,
+ .resume = mxc_v4l2_resume,
+ .shutdown = NULL,
+ },
+ {
+ .driver = {
+ .name = "mxc_v4l2_2",
+ },
+ .probe = NULL,
+ .remove = NULL,
+ .suspend = mxc_v4l2_suspend,
+ .resume = mxc_v4l2_resume,
+ .shutdown = NULL,
+ },
};
/*!
@@ -2567,6 +2676,7 @@ static int mxc_v4l2_master_attach(struct v4l2_int_device *slave)
}
ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true);
+ vidioc_int_s_power(cam->sensor, 1);
vidioc_int_dev_init(slave);
ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false);
cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -2623,53 +2733,55 @@ static void mxc_v4l2_master_detach(struct v4l2_int_device *slave)
static __init int camera_init(void)
{
u8 err = 0;
+ int i;
pr_debug("In MVC:camera_init\n");
- /* Register the device driver structure. */
- err = platform_driver_register(&mxc_v4l2_driver);
- if (err != 0) {
- pr_err("ERROR: v4l2 capture:camera_init: "
- "platform_driver_register failed.\n");
- return err;
- }
+ for (i = 0; i < ARRAY_SIZE(mxc_v4l2_int_device); i++) {
+ /* Register the device driver structure. */
+ err = platform_driver_register(&mxc_v4l2_driver[i]);
+ if (err != 0) {
+ pr_err("ERROR: v4l2 capture:camera_init: "
+ "platform_driver_register failed.\n");
+ return err;
+ }
- /* Create g_cam and initialize it. */
- if ((g_cam = kmalloc(sizeof(cam_data), GFP_KERNEL)) == NULL) {
- pr_err("ERROR: v4l2 capture: failed to register camera\n");
- platform_driver_unregister(&mxc_v4l2_driver);
- return -1;
- }
- init_camera_struct(g_cam);
+ /* Create g_cam and initialize it. */
+ if ((g_cam [i] = kmalloc(sizeof(cam_data), GFP_KERNEL)) == NULL) {
+ pr_err("ERROR: v4l2 capture: failed to register camera\n");
+ platform_driver_unregister(&mxc_v4l2_driver[i]);
+ return -1;
+ }
+ init_camera_struct(g_cam [i], i);
- /* Set up the v4l2 device and register it*/
- mxc_v4l2_int_device.priv = g_cam;
- /* This function contains a bug that won't let this be rmmod'd. */
- v4l2_int_device_register(&mxc_v4l2_int_device);
+ /* Set up the v4l2 device and register it*/
+ mxc_v4l2_int_device[i].priv = g_cam [i];
+ /* This function contains a bug that won't let this be rmmod'd. */
+ v4l2_int_device_register(&mxc_v4l2_int_device[i]);
- /* Register the I2C device */
- err = platform_device_register(&mxc_v4l2_devices);
- if (err != 0) {
- pr_err("ERROR: v4l2 capture: camera_init: "
- "platform_device_register failed.\n");
- platform_driver_unregister(&mxc_v4l2_driver);
- kfree(g_cam);
- g_cam = NULL;
- return err;
- }
+ /* Register the I2C device */
+ err = platform_device_register(&mxc_v4l2_devices[i]);
+ if (err != 0) {
+ pr_err("ERROR: v4l2 capture: camera_init: "
+ "platform_device_register failed.\n");
+ platform_driver_unregister(&mxc_v4l2_driver[i]);
+ kfree(g_cam [i]);
+ g_cam [i] = NULL;
+ return err;
+ }
- /* register v4l video device */
- if (video_register_device(g_cam->video_dev, VFL_TYPE_GRABBER, video_nr)
- == -1) {
- platform_device_unregister(&mxc_v4l2_devices);
- platform_driver_unregister(&mxc_v4l2_driver);
- kfree(g_cam);
- g_cam = NULL;
- pr_err("ERROR: v4l2 capture: video_register_device failed\n");
- return -1;
+ /* register v4l video device */
+ if (video_register_device(g_cam[i]->video_dev, VFL_TYPE_GRABBER, video_nr)== -1) {
+ platform_device_unregister(&mxc_v4l2_devices[i]);
+ platform_driver_unregister(&mxc_v4l2_driver[i]);
+ kfree(g_cam[i]);
+ g_cam [i] = NULL;
+ pr_err("ERROR: v4l2 capture: video_register_device failed\n");
+ return -1;
+ }
+ pr_debug(" Video device registered: %s #%d\n",
+ g_cam[i]->video_dev->name, g_cam[i]->video_dev->minor);
}
- pr_debug(" Video device registered: %s #%d\n",
- g_cam->video_dev->name, g_cam->video_dev->minor);
return err;
}
@@ -2683,19 +2795,34 @@ static void __exit camera_exit(void)
pr_info("V4L2 unregistering video\n");
- if (g_cam->open_count) {
+ if (g_cam[0]->open_count) {
+ pr_err("ERROR: v4l2 capture:camera open "
+ "-- setting ops to NULL\n");
+ } else {
+ pr_info("V4L2 freeing image input device\n");
+ v4l2_int_device_unregister(&mxc_v4l2_int_device[0]);
+ video_unregister_device(g_cam[0]->video_dev);
+ platform_driver_unregister(&mxc_v4l2_driver[0]);
+ platform_device_unregister(&mxc_v4l2_devices[0]);
+
+ mxc_free_frame_buf(g_cam[0]);
+ kfree(g_cam[0]);
+ g_cam[0] = NULL;
+ }
+
+ if (g_cam[1]->open_count) {
pr_err("ERROR: v4l2 capture:camera open "
"-- setting ops to NULL\n");
} else {
pr_info("V4L2 freeing image input device\n");
- v4l2_int_device_unregister(&mxc_v4l2_int_device);
- video_unregister_device(g_cam->video_dev);
- platform_driver_unregister(&mxc_v4l2_driver);
- platform_device_unregister(&mxc_v4l2_devices);
-
- mxc_free_frame_buf(g_cam);
- kfree(g_cam);
- g_cam = NULL;
+ v4l2_int_device_unregister(&mxc_v4l2_int_device[1]);
+ video_unregister_device(g_cam[1]->video_dev);
+ platform_driver_unregister(&mxc_v4l2_driver[1]);
+ platform_device_unregister(&mxc_v4l2_devices[1]);
+
+ mxc_free_frame_buf(g_cam[1]);
+ kfree(g_cam[1]);
+ g_cam[1] = NULL;
}
}
diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h
index 45a211a80a38..abaaaea48447 100644
--- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h
+++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h
@@ -36,6 +36,7 @@
#include <media/v4l2-dev.h>
#define FRAME_NUM 3
+//#define FRAME_NUM 4
/*!
* v4l2 frame structure.
@@ -123,7 +124,7 @@ typedef struct _cam_data {
/* still image capture */
wait_queue_head_t still_queue;
int still_counter;
- dma_addr_t still_buf;
+ dma_addr_t still_buf[2];
void *still_buf_vaddr;
/* overlay */
@@ -166,7 +167,7 @@ typedef struct _cam_data {
struct v4l2_rect crop_defrect;
struct v4l2_rect crop_current;
- int (*enc_update_eba) (dma_addr_t eba, int *bufferNum);
+ int (*enc_update_eba) (int csi,dma_addr_t eba, int *bufferNum);
int (*enc_enable) (void *private);
int (*enc_disable) (void *private);
int (*enc_enable_csi) (void *private);
@@ -194,6 +195,7 @@ typedef struct _cam_data {
/* camera sensor interface */
struct camera_sensor *cam_sensor; /* old version */
struct v4l2_int_device *sensor;
+ struct timeval tv_wakeup; // TODO - for testing. Remove later
} cam_data;
#if defined(CONFIG_MXC_IPU_V1) || defined(CONFIG_VIDEO_MXC_EMMA_CAMERA) \
diff --git a/drivers/media/video/mxc/capture/ov3640.c b/drivers/media/video/mxc/capture/ov3640.c
index 29e61234e7f8..899945b7d071 100644
--- a/drivers/media/video/mxc/capture/ov3640.c
+++ b/drivers/media/video/mxc/capture/ov3640.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -26,7 +26,7 @@
#define OV3640_VOLTAGE_ANALOG 2800000
#define OV3640_VOLTAGE_DIGITAL_CORE 1500000
#define OV3640_VOLTAGE_DIGITAL_IO 1800000
-
+#define OV3640_VOLTAGE_DIGITAL_GPO 2800000
/* Check these values! */
#define MIN_FPS 15
@@ -40,8 +40,8 @@ enum ov3640_mode {
ov3640_mode_MIN = 0,
ov3640_mode_VGA_640_480 = 0,
ov3640_mode_QVGA_320_240 = 1,
- ov3640_mode_QXGA_2048_1536 = 2,
- ov3640_mode_XGA_1024_768 = 3,
+ ov3640_mode_XGA_1024_768 = 2,
+ ov3640_mode_QXGA_2048_1536 = 3,
ov3640_mode_NTSC_720_480 = 4,
ov3640_mode_PAL_720_576 = 5,
ov3640_mode_MAX = 5
@@ -93,6 +93,44 @@ struct sensor {
} ov3640_data;
static struct reg_value ov3640_setting_15fps_QXGA_2048_1536[] = {
+#if 0
+ /* The true 15fps QXGA setting. */
+ {0x3012, 0x80, 0, 0}, {0x304d, 0x41, 0, 0}, {0x3087, 0x16, 0, 0},
+ {0x30aa, 0x45, 0, 0}, {0x30b0, 0xff, 0, 0}, {0x30b1, 0xff, 0, 0},
+ {0x30b2, 0x13, 0, 0}, {0x30d7, 0x10, 0, 0}, {0x309e, 0x00, 0, 0},
+ {0x3602, 0x26, 0, 0}, {0x3603, 0x4D, 0, 0}, {0x364c, 0x04, 0, 0},
+ {0x360c, 0x12, 0, 0}, {0x361e, 0x00, 0, 0}, {0x361f, 0x11, 0, 0},
+ {0x3633, 0x03, 0, 0}, {0x3629, 0x3c, 0, 0}, {0x300e, 0x33, 0, 0},
+ {0x300f, 0x21, 0, 0}, {0x3010, 0x20, 0, 0}, {0x3011, 0x00, 0, 0},
+ {0x304c, 0x81, 0, 0}, {0x3029, 0x47, 0, 0}, {0x3070, 0x00, 0, 0},
+ {0x3071, 0xEC, 0, 0}, {0x301C, 0x06, 0, 0}, {0x3072, 0x00, 0, 0},
+ {0x3073, 0xC5, 0, 0}, {0x301D, 0x07, 0, 0}, {0x3018, 0x38, 0, 0},
+ {0x3019, 0x30, 0, 0}, {0x301a, 0x61, 0, 0}, {0x307d, 0x00, 0, 0},
+ {0x3087, 0x02, 0, 0}, {0x3082, 0x20, 0, 0}, {0x303c, 0x08, 0, 0},
+ {0x303d, 0x18, 0, 0}, {0x303e, 0x06, 0, 0}, {0x303F, 0x0c, 0, 0},
+ {0x3030, 0x62, 0, 0}, {0x3031, 0x26, 0, 0}, {0x3032, 0xe6, 0, 0},
+ {0x3033, 0x6e, 0, 0}, {0x3034, 0xea, 0, 0}, {0x3035, 0xae, 0, 0},
+ {0x3036, 0xa6, 0, 0}, {0x3037, 0x6a, 0, 0}, {0x3015, 0x12, 0, 0},
+ {0x3014, 0x04, 0, 0}, {0x3013, 0xf7, 0, 0}, {0x3104, 0x02, 0, 0},
+ {0x3105, 0xfd, 0, 0}, {0x3106, 0x00, 0, 0}, {0x3107, 0xff, 0, 0},
+ {0x3308, 0xa5, 0, 0}, {0x3316, 0xff, 0, 0}, {0x3317, 0x00, 0, 0},
+ {0x3087, 0x02, 0, 0}, {0x3082, 0x20, 0, 0}, {0x3300, 0x13, 0, 0},
+ {0x3301, 0xd6, 0, 0}, {0x3302, 0xef, 0, 0}, {0x30b8, 0x20, 0, 0},
+ {0x30b9, 0x17, 0, 0}, {0x30ba, 0x04, 0, 0}, {0x30bb, 0x08, 0, 0},
+ {0x3100, 0x02, 0, 0}, {0x3304, 0x00, 0, 0}, {0x3400, 0x00, 0, 0},
+ {0x3404, 0x02, 0, 0}, {0x3020, 0x01, 0, 0}, {0x3021, 0x1d, 0, 0},
+ {0x3022, 0x00, 0, 0}, {0x3023, 0x0a, 0, 0}, {0x3024, 0x08, 0, 0},
+ {0x3025, 0x18, 0, 0}, {0x3026, 0x06, 0, 0}, {0x3027, 0x0c, 0, 0},
+ {0x335f, 0x68, 0, 0}, {0x3360, 0x18, 0, 0}, {0x3361, 0x0c, 0, 0},
+ {0x3362, 0x68, 0, 0}, {0x3363, 0x08, 0, 0}, {0x3364, 0x04, 0, 0},
+ {0x3403, 0x42, 0, 0}, {0x3088, 0x08, 0, 0}, {0x3089, 0x00, 0, 0},
+ {0x308a, 0x06, 0, 0}, {0x308b, 0x00, 0, 0}, {0x3507, 0x06, 0, 0},
+ {0x350a, 0x4f, 0, 0}, {0x3600, 0xc4, 0, 0},
+#endif
+ /*
+ * Only support 7.5fps for QXGA to workaround screen tearing issue
+ * for 15fps when capturing still image.
+ */
{0x3012, 0x80, 0, 0}, {0x304d, 0x45, 0, 0}, {0x30a7, 0x5e, 0, 0},
{0x3087, 0x16, 0, 0}, {0x309c, 0x1a, 0, 0}, {0x30a2, 0xe4, 0, 0},
{0x30aa, 0x42, 0, 0}, {0x30b0, 0xff, 0, 0}, {0x30b1, 0xff, 0, 0},
@@ -118,25 +156,9 @@ static struct reg_value ov3640_setting_15fps_QXGA_2048_1536[] = {
{0x30bb, 0x08, 0, 0}, {0x3507, 0x06, 0, 0}, {0x350a, 0x4f, 0, 0},
{0x3100, 0x02, 0, 0}, {0x3301, 0xde, 0, 0}, {0x3304, 0x00, 0, 0},
{0x3400, 0x00, 0, 0}, {0x3404, 0x02, 0, 0}, {0x3600, 0xc4, 0, 0},
- {0x3302, 0xef, 0, 0}, {0x3020, 0x01, 0, 0}, {0x3021, 0x1d, 0, 0},
- {0x3022, 0x00, 0, 0}, {0x3023, 0x0a, 0, 0}, {0x3024, 0x08, 0, 0},
- {0x3025, 0x00, 0, 0}, {0x3026, 0x06, 0, 0}, {0x3027, 0x00, 0, 0},
- {0x335f, 0x68, 0, 0}, {0x3360, 0x00, 0, 0}, {0x3361, 0x00, 0, 0},
- {0x3362, 0x68, 0, 0}, {0x3363, 0x00, 0, 0}, {0x3364, 0x00, 0, 0},
- {0x3403, 0x00, 0, 0}, {0x3088, 0x08, 0, 0}, {0x3089, 0x00, 0, 0},
- {0x308a, 0x06, 0, 0}, {0x308b, 0x00, 0, 0}, {0x307c, 0x10, 0, 0},
- {0x3090, 0xc0, 0, 0}, {0x304c, 0x84, 0, 0}, {0x308d, 0x04, 0, 0},
- {0x3086, 0x03, 0, 0}, {0x3086, 0x00, 0, 0}, {0x3012, 0x00, 0, 0},
- {0x3020, 0x01, 0, 0}, {0x3021, 0x1d, 0, 0}, {0x3022, 0x00, 0, 0},
- {0x3023, 0x0a, 0, 0}, {0x3024, 0x08, 0, 0}, {0x3025, 0x18, 0, 0},
- {0x3026, 0x06, 0, 0}, {0x3027, 0x0c, 0, 0}, {0x302a, 0x06, 0, 0},
- {0x302b, 0x20, 0, 0}, {0x3075, 0x44, 0, 0}, {0x300d, 0x00, 0, 0},
- {0x30d7, 0x00, 0, 0}, {0x3069, 0x40, 0, 0}, {0x303e, 0x01, 0, 0},
- {0x303f, 0x80, 0, 0}, {0x3302, 0x20, 0, 0}, {0x335f, 0x68, 0, 0},
- {0x3360, 0x18, 0, 0}, {0x3361, 0x0c, 0, 0}, {0x3362, 0x68, 0, 0},
- {0x3363, 0x08, 0, 0}, {0x3364, 0x04, 0, 0}, {0x3403, 0x42, 0, 0},
{0x3088, 0x08, 0, 0}, {0x3089, 0x00, 0, 0}, {0x308a, 0x06, 0, 0},
- {0x308b, 0x00, 0, 0},
+ {0x308b, 0x00, 0, 0}, {0x308d, 0x04, 0, 0}, {0x3086, 0x03, 0, 0},
+ {0x3086, 0x00, 0, 0}, {0x3011, 0x01, 0, 0},
};
static struct reg_value ov3640_setting_15fps_XGA_1024_768[] = {
@@ -674,6 +696,7 @@ static struct regulator *io_regulator;
static struct regulator *core_regulator;
static struct regulator *analog_regulator;
static struct regulator *gpo_regulator;
+static struct mxc_camera_platform_data *camera_plat;
static int ov3640_probe(struct i2c_client *adapter,
const struct i2c_device_id *device_id);
@@ -843,6 +866,10 @@ static int ioctl_s_power(struct v4l2_int_device *s, int on)
if (analog_regulator)
if (regulator_enable(analog_regulator) != 0)
return -EIO;
+ /* Make sure power on */
+ if (camera_plat->pwdn)
+ camera_plat->pwdn(0);
+
} else if (!on && sensor->on) {
if (analog_regulator)
regulator_disable(analog_regulator);
@@ -920,6 +947,10 @@ static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
enum ov3640_frame_rate frame_rate;
int ret = 0;
+ /* Make sure power on */
+ if (camera_plat->pwdn)
+ camera_plat->pwdn(0);
+
switch (a->type) {
/* This is the only case currently handled. */
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -1286,17 +1317,25 @@ static int ov3640_probe(struct i2c_client *client,
gpo_regulator = regulator_get(&client->dev,
plat_data->gpo_regulator);
if (!IS_ERR(gpo_regulator)) {
+ regulator_set_voltage(gpo_regulator,
+ OV3640_VOLTAGE_DIGITAL_GPO,
+ OV3640_VOLTAGE_DIGITAL_GPO);
if (regulator_enable(gpo_regulator) != 0) {
- pr_err("%s:gpo3 enable error\n", __func__);
+ pr_err("%s:gpo enable error\n", __func__);
goto err4;
} else {
dev_dbg(&client->dev,
- "%s:gpo3 enable ok\n", __func__);
+ "%s:gpo enable ok\n", __func__);
}
} else
gpo_regulator = NULL;
}
+ if (plat_data->pwdn)
+ plat_data->pwdn(0);
+
+ camera_plat = plat_data;
+
ov3640_int_device.priv = &ov3640_data;
retval = v4l2_int_device_register(&ov3640_int_device);
diff --git a/drivers/media/video/mxc/output/Makefile b/drivers/media/video/mxc/output/Makefile
index 1713fa3bf3ab..500442544902 100644
--- a/drivers/media/video/mxc/output/Makefile
+++ b/drivers/media/video/mxc/output/Makefile
@@ -6,6 +6,9 @@ endif
ifeq ($(CONFIG_VIDEO_MXC_IPU_OUTPUT),y)
obj-$(CONFIG_VIDEO_MXC_OUTPUT) += mxc_v4l2_output.o
endif
+ifeq ($(CONFIG_VIDEO_MXC_PXP_V4L2),y)
+ obj-$(CONFIG_VIDEO_MXC_PXP_V4L2) += mxc_pxp_v4l2.o
+endif
ifeq ($(CONFIG_VIDEO_MXC_IPUV1_WVGA_OUTPUT),y)
obj-$(CONFIG_VIDEO_MXC_OUTPUT) += mx31_v4l2_wvga_output.o
endif
diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.c b/drivers/media/video/mxc/output/mxc_v4l2_output.c
index 408f9b7871a8..b7bbfed73019 100644
--- a/drivers/media/video/mxc/output/mxc_v4l2_output.c
+++ b/drivers/media/video/mxc/output/mxc_v4l2_output.c
@@ -44,9 +44,7 @@ vout_data *g_vout;
#define LOAD_3FIELDS(vout) ((INTERLACED_CONTENT(vout)) && \
((vout)->motion_sel != HIGH_MOTION))
-#define SDC_FG_FB_FORMAT IPU_PIX_FMT_RGB565
-
-struct v4l2_output mxc_outputs[2] = {
+struct v4l2_output mxc_outputs[1] = {
{
.index = MXC_V4L2_OUT_2_SDC,
.name = "DISP3 Video Out",
@@ -54,23 +52,14 @@ struct v4l2_output mxc_outputs[2] = {
but no other choice */
.audioset = 0,
.modulator = 0,
- .std = V4L2_STD_UNKNOWN},
- {
- .index = MXC_V4L2_OUT_2_ADC,
- .name = "DISPx Video Out",
- .type = V4L2_OUTPUT_TYPE_ANALOG, /* not really correct,
- but no other choice */
- .audioset = 0,
- .modulator = 0,
.std = V4L2_STD_UNKNOWN}
};
static int video_nr = 16;
static spinlock_t g_lock = SPIN_LOCK_UNLOCKED;
static int last_index_n;
-static int last_index_c;
static unsigned int ipu_ic_out_max_width_size;
-
+static unsigned int ipu_ic_out_max_height_size;
/* debug counters */
uint32_t g_irq_cnt;
uint32_t g_buf_output_cnt;
@@ -256,10 +245,14 @@ static int select_display_buffer(vout_data *vout, int next_buf)
{
int ret = 0;
+ vout->disp_buf_num = next_buf;
if (ipu_get_cur_buffer_idx(vout->display_ch, IPU_INPUT_BUFFER)
!= next_buf)
ret = ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER,
next_buf);
+ else
+ dev_dbg(&vout->video_dev->dev,
+ "display buffer not ready for select\n");
return ret;
}
@@ -290,110 +283,138 @@ static void setup_next_buf_timer(vout_data *vout, int index)
"timer handler next schedule: %lu\n", timeout);
}
-static int wait_for_disp_vsync(vout_data *vout)
+static int finish_previous_frame(vout_data *vout)
{
struct fb_info *fbi =
registered_fb[vout->output_fb_num[vout->cur_disp_output]];
mm_segment_t old_fs;
int ret = 0;
- /* wait for display frame finish */
- if (fbi->fbops->fb_ioctl) {
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- ret = fbi->fbops->fb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC,
- (unsigned int)NULL);
- set_fs(old_fs);
+ /* make sure buf[vout->disp_buf_num] in showing */
+ while (ipu_check_buffer_busy(vout->display_ch,
+ IPU_INPUT_BUFFER, vout->disp_buf_num)) {
+ if (fbi->fbops->fb_ioctl) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = fbi->fbops->fb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC,
+ (unsigned int)NULL);
+ set_fs(old_fs);
+
+ if (ret < 0) {
+ /* ic_bypass need clear display buffer ready for next update*/
+ ipu_clear_buffer_ready(vout->display_ch, IPU_INPUT_BUFFER,
+ vout->disp_buf_num);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int show_current_frame(vout_data *vout)
+{
+ struct fb_info *fbi =
+ registered_fb[vout->output_fb_num[vout->cur_disp_output]];
+ mm_segment_t old_fs;
+ int ret = 0;
+
+ /* make sure buf[vout->disp_buf_num] begin to show */
+ if (ipu_get_cur_buffer_idx(vout->display_ch, IPU_INPUT_BUFFER)
+ != vout->disp_buf_num) {
+ /* wait for display frame finish */
+ if (fbi->fbops->fb_ioctl) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = fbi->fbops->fb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC,
+ (unsigned int)NULL);
+ set_fs(old_fs);
+ }
}
+
return ret;
}
-static void timer_work_func(struct work_struct *work)
+static void icbypass_work_func(struct work_struct *work)
{
vout_data *vout =
- container_of(work, vout_data, timer_work);
+ container_of(work, vout_data, icbypass_work);
int index, ret;
int last_buf;
unsigned long lock_flags = 0;
- /* wait 2 first frame finish for ic bypass mode*/
- if ((g_buf_output_cnt == 0) && vout->ic_bypass) {
- wait_for_disp_vsync(vout);
- wait_for_disp_vsync(vout);
- spin_lock_irqsave(&g_lock, lock_flags);
- last_buf = vout->ipu_buf[0];
- vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE;
- queue_buf(&vout->done_q, last_buf);
- vout->ipu_buf[0] = -1;
- last_buf = vout->ipu_buf[1];
- vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE;
- queue_buf(&vout->done_q, last_buf);
- vout->ipu_buf[1] = -1;
- g_buf_output_cnt = 2;
- wake_up_interruptible(&vout->v4l_bufq);
- if (vout->state == STATE_STREAM_PAUSED) {
- index = peek_next_buf(&vout->ready_q);
- if (index != -1) {
- /* Setup timer for next buffer, when stream has been paused */
- pr_debug("next index %d\n", index);
- setup_next_buf_timer(vout, index);
- vout->state = STATE_STREAM_ON;
- }
- }
- spin_unlock_irqrestore(&g_lock, lock_flags);
- return;
- }
-
- if (wait_for_disp_vsync(vout) < 0) {
- /* ic_bypass need clear display buffer ready for next update*/
- ipu_clear_buffer_ready(vout->display_ch, IPU_INPUT_BUFFER,
- !vout->next_done_ipu_buf);
- }
+ finish_previous_frame(vout);
spin_lock_irqsave(&g_lock, lock_flags);
- if (vout->ic_bypass) {
- last_buf = vout->ipu_buf[vout->next_done_ipu_buf];
- if (last_buf != -1) {
- g_buf_output_cnt++;
- vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE;
- queue_buf(&vout->done_q, last_buf);
- wake_up_interruptible(&vout->v4l_bufq);
- vout->ipu_buf[vout->next_done_ipu_buf] = -1;
- vout->next_done_ipu_buf = !vout->next_done_ipu_buf;
- }
+ index = dequeue_buf(&vout->ready_q);
+ if (index == -1) { /* no buffers ready, should never occur */
+ dev_err(&vout->video_dev->dev,
+ "mxc_v4l2out: timer - no queued buffers ready\n");
+ goto exit;
}
+ g_buf_dq_cnt++;
+ vout->frame_count++;
- if (vout->ic_bypass)
- ret = select_display_buffer(vout, vout->next_rdy_ipu_buf);
- else if (LOAD_3FIELDS(vout))
- ret = ipu_select_multi_vdi_buffer(vout->next_rdy_ipu_buf);
- else
- ret = ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER,
- vout->next_rdy_ipu_buf);
+ vout->ipu_buf[vout->next_rdy_ipu_buf] = index;
+ ret = ipu_update_channel_buffer(vout->display_ch, IPU_INPUT_BUFFER,
+ vout->next_rdy_ipu_buf,
+ vout->v4l2_bufs[index].m.offset);
+ ret += select_display_buffer(vout, vout->next_rdy_ipu_buf);
if (ret < 0) {
dev_err(&vout->video_dev->dev,
- "unable to set IPU buffer ready\n");
+ "unable to update buffer %d address rc=%d\n",
+ vout->next_rdy_ipu_buf, ret);
+ goto exit;
}
+ spin_unlock_irqrestore(&g_lock, lock_flags);
+ show_current_frame(vout);
+ spin_lock_irqsave(&g_lock, lock_flags);
+ vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf;
- /* Non IC split action */
- if (!vout->pp_split)
- vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf;
+ last_buf = vout->ipu_buf[vout->next_done_ipu_buf];
+ if (last_buf != -1) {
+ g_buf_output_cnt++;
+ vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE;
+ queue_buf(&vout->done_q, last_buf);
+ wake_up_interruptible(&vout->v4l_bufq);
+ vout->ipu_buf[vout->next_done_ipu_buf] = -1;
+ vout->next_done_ipu_buf = !vout->next_done_ipu_buf;
+ }
- /* Setup timer for next buffer */
- index = peek_next_buf(&vout->ready_q);
- if (index != -1)
- setup_next_buf_timer(vout, index);
- else
- vout->state = STATE_STREAM_PAUSED;
+ if (g_buf_output_cnt > 0) {
+ /* Setup timer for next buffer */
+ index = peek_next_buf(&vout->ready_q);
+ if (index != -1)
+ setup_next_buf_timer(vout, index);
+ else
+ vout->state = STATE_STREAM_PAUSED;
+ if (vout->state == STATE_STREAM_STOPPING) {
+ if ((vout->ipu_buf[0] == -1) && (vout->ipu_buf[1] == -1)) {
+ vout->state = STATE_STREAM_OFF;
+ }
+ }
+ }
+exit:
spin_unlock_irqrestore(&g_lock, lock_flags);
+}
- if (vout->state == STATE_STREAM_STOPPING) {
- if ((vout->ipu_buf[0] == -1) && (vout->ipu_buf[1] == -1)) {
- vout->state = STATE_STREAM_OFF;
- }
+static int get_cur_fb_blank(vout_data *vout)
+{
+ struct fb_info *fbi =
+ registered_fb[vout->output_fb_num[vout->cur_disp_output]];
+ mm_segment_t old_fs;
+ int ret = 0;
+
+ if (fbi->fbops->fb_ioctl) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_BLANK,
+ (unsigned int)(&vout->fb_blank));
+ set_fs(old_fs);
}
+
+ return ret;
}
static void mxc_v4l2out_timer_handler(unsigned long arg)
@@ -401,13 +422,13 @@ static void mxc_v4l2out_timer_handler(unsigned long arg)
int index, ret;
unsigned long lock_flags = 0;
vout_data *vout = (vout_data *) arg;
- unsigned int aid_field_offset = 0, current_field_offset = 0;
spin_lock_irqsave(&g_lock, lock_flags);
if ((vout->state == STATE_STREAM_STOPPING)
|| (vout->state == STATE_STREAM_OFF))
goto exit0;
+
/*
* If timer occurs before IPU h/w is ready, then set the state to
* paused and the timer will be set again when next buffer is queued
@@ -419,98 +440,92 @@ static void mxc_v4l2out_timer_handler(unsigned long arg)
goto exit0;
}
- /* Dequeue buffer and pass to IPU */
- if (INTERLACED_CONTENT(vout)) {
- if (((LOAD_3FIELDS(vout)) && (vout->next_rdy_ipu_buf)) ||
- ((!LOAD_3FIELDS(vout)) && !(vout->next_rdy_ipu_buf))) {
- aid_field_offset = vout->bytesperline;
- current_field_offset = 0;
- index = last_index_n;
- } else {
- aid_field_offset = 0;
- current_field_offset = vout->bytesperline;
- index = dequeue_buf(&vout->ready_q);
- if (index == -1) { /* no buffers ready, should never occur */
- dev_err(&vout->video_dev->dev,
- "mxc_v4l2out: timer - no queued buffers ready\n");
- goto exit0;
- }
- g_buf_dq_cnt++;
- vout->frame_count++;
- last_index_n = index;
- }
- } else {
- current_field_offset = 0;
- index = dequeue_buf(&vout->ready_q);
- if (index == -1) { /* no buffers ready, should never occur */
+ /* VDI need both buffer done before update buffer? */
+ if (INTERLACED_CONTENT(vout) &&
+ (vout->ipu_buf[!vout->next_rdy_ipu_buf] != -1)) {
+ dev_dbg(&vout->video_dev->dev, "IPU buffer busy\n");
+ vout->state = STATE_STREAM_PAUSED;
+ goto exit0;
+ }
+
+ /* Handle ic bypass mode in work queue */
+ if (vout->ic_bypass) {
+ if (queue_work(vout->v4l_wq, &vout->icbypass_work) == 0) {
dev_err(&vout->video_dev->dev,
- "mxc_v4l2out: timer - no queued buffers ready\n");
- goto exit0;
+ "ic bypass work was in queue already!\n ");
+ vout->state = STATE_STREAM_PAUSED;
}
- g_buf_dq_cnt++;
- vout->frame_count++;
+ goto exit0;
+ } else if (!vout->fb_blank &&
+ (ipu_get_cur_buffer_idx(vout->display_ch, IPU_INPUT_BUFFER)
+ == vout->next_disp_ipu_buf)) {
+ dev_dbg(&vout->video_dev->dev, "IPU disp busy\n");
+ get_cur_fb_blank(vout);
+ index = peek_next_buf(&vout->ready_q);
+ setup_next_buf_timer(vout, index);
+ goto exit0;
}
+ vout->fb_blank = 0;
+
+ /* Dequeue buffer and pass to IPU */
+ index = dequeue_buf(&vout->ready_q);
+ if (index == -1) { /* no buffers ready, should never occur */
+ dev_err(&vout->video_dev->dev,
+ "mxc_v4l2out: timer - no queued buffers ready\n");
+ goto exit0;
+ }
+ g_buf_dq_cnt++;
+ vout->frame_count++;
/* update next buffer */
- if (vout->ic_bypass) {
+ if (LOAD_3FIELDS(vout)) {
+ int index_n = index;
+ int index_p = last_index_n;
+ vout->ipu_buf_p[vout->next_rdy_ipu_buf] = last_index_n;
vout->ipu_buf[vout->next_rdy_ipu_buf] = index;
- ret = ipu_update_channel_buffer(vout->display_ch, IPU_INPUT_BUFFER,
- vout->next_rdy_ipu_buf,
- vout->v4l2_bufs[index].m.offset);
+ vout->ipu_buf_n[vout->next_rdy_ipu_buf] = index;
+ ret = ipu_update_channel_buffer(vout->post_proc_ch,
+ IPU_INPUT_BUFFER,
+ vout->next_rdy_ipu_buf,
+ vout->v4l2_bufs[index].m.offset);
+ ret += ipu_update_channel_buffer(MEM_VDI_PRP_VF_MEM_P,
+ IPU_INPUT_BUFFER,
+ vout->next_rdy_ipu_buf,
+ vout->v4l2_bufs[index_p].m.offset + vout->bytesperline);
+ ret += ipu_update_channel_buffer(MEM_VDI_PRP_VF_MEM_N,
+ IPU_INPUT_BUFFER,
+ vout->next_rdy_ipu_buf,
+ vout->v4l2_bufs[index_n].m.offset) + vout->bytesperline;
+ last_index_n = index;
} else {
- if (LOAD_3FIELDS(vout)) {
- int index_n = index;
- int index_p = last_index_c;
- index = last_index_n;
- vout->ipu_buf_p[vout->next_rdy_ipu_buf] = index_p;
- vout->ipu_buf[vout->next_rdy_ipu_buf] = last_index_c = index;
- vout->ipu_buf_n[vout->next_rdy_ipu_buf] = last_index_n = index_n;
- last_index_n = vout->ipu_buf_n[vout->next_rdy_ipu_buf];
- last_index_c = vout->ipu_buf[vout->next_rdy_ipu_buf];
+ vout->ipu_buf[vout->next_rdy_ipu_buf] = index;
+ if (vout->pp_split) {
+ vout->ipu_buf[!vout->next_rdy_ipu_buf] = index;
+ /* always left stripe */
ret = ipu_update_channel_buffer(vout->post_proc_ch,
- IPU_INPUT_BUFFER,
- vout->next_rdy_ipu_buf,
- vout->v4l2_bufs[index].m.offset+current_field_offset);
- ret += ipu_update_channel_buffer(MEM_VDI_PRP_VF_MEM_P,
- IPU_INPUT_BUFFER,
- vout->next_rdy_ipu_buf,
- vout->v4l2_bufs[index_p].m.offset+aid_field_offset);
- ret += ipu_update_channel_buffer(MEM_VDI_PRP_VF_MEM_N,
- IPU_INPUT_BUFFER,
- vout->next_rdy_ipu_buf,
- vout->v4l2_bufs[index_n].m.offset+aid_field_offset);
- } else {
- vout->ipu_buf[vout->next_rdy_ipu_buf] = index;
- if (vout->pp_split) {
- vout->ipu_buf[!vout->next_rdy_ipu_buf] = index;
- /* always left stripe */
- ret = ipu_update_channel_buffer(vout->post_proc_ch,
- IPU_INPUT_BUFFER,
- 0,/* vout->next_rdy_ipu_buf,*/
- (vout->v4l2_bufs[index].m.offset) +
- vout->pp_left_stripe.input_column +
- current_field_offset);
-
- /* the U/V offset has to be updated inside of IDMAC */
- /* according to stripe offset */
- ret += ipu_update_channel_offset(vout->post_proc_ch,
- IPU_INPUT_BUFFER,
- vout->v2f.fmt.pix.pixelformat,
- vout->v2f.fmt.pix.width,
- vout->v2f.fmt.pix.height,
- vout->bytesperline,
- vout->offset.u_offset,
- vout->offset.v_offset,
- 0,
- vout->pp_left_stripe.input_column + current_field_offset);
-
- } else
- ret = ipu_update_channel_buffer(vout->post_proc_ch,
- IPU_INPUT_BUFFER,
- vout->next_rdy_ipu_buf,
- vout->v4l2_bufs[index].m.offset +
- current_field_offset);
- }
+ IPU_INPUT_BUFFER,
+ 0,/* vout->next_rdy_ipu_buf,*/
+ (vout->v4l2_bufs[index].m.offset) +
+ vout->pp_left_stripe.input_column +
+ vout->pp_up_stripe.input_column * vout->bytesperline);
+
+ /* the U/V offset has to be updated inside of IDMAC */
+ /* according to stripe offset */
+ ret += ipu_update_channel_offset(vout->post_proc_ch,
+ IPU_INPUT_BUFFER,
+ vout->v2f.fmt.pix.pixelformat,
+ vout->v2f.fmt.pix.width,
+ vout->v2f.fmt.pix.height,
+ vout->bytesperline,
+ vout->offset.u_offset,
+ vout->offset.v_offset,
+ vout->pp_up_stripe.input_column,
+ vout->pp_left_stripe.input_column);
+ } else
+ ret = ipu_update_channel_buffer(vout->post_proc_ch,
+ IPU_INPUT_BUFFER,
+ vout->next_rdy_ipu_buf,
+ vout->v4l2_bufs[index].m.offset);
}
if (ret < 0) {
@@ -521,9 +536,35 @@ static void mxc_v4l2out_timer_handler(unsigned long arg)
}
/* set next buffer ready */
- if (queue_work(vout->v4l_wq, &vout->timer_work) == 0) {
- dev_err(&vout->video_dev->dev, "work was in queue already!\n ");
+ if (LOAD_3FIELDS(vout))
+ ret = ipu_select_multi_vdi_buffer(vout->next_rdy_ipu_buf);
+ else
+ ret = ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER,
+ vout->next_rdy_ipu_buf);
+ if (ret < 0) {
+ dev_err(&vout->video_dev->dev,
+ "unable to set IPU buffer ready\n");
+ goto exit0;
+ }
+
+ /* Split mode use buf 0 only, no need swith buf */
+ if (!vout->pp_split)
+ vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf;
+
+ /* Always assume display in double buffers */
+ vout->next_disp_ipu_buf = !vout->next_disp_ipu_buf;
+
+ /* Setup timer for next buffer */
+ index = peek_next_buf(&vout->ready_q);
+ if (index != -1)
+ setup_next_buf_timer(vout, index);
+ else
vout->state = STATE_STREAM_PAUSED;
+
+ if (vout->state == STATE_STREAM_STOPPING) {
+ if ((vout->ipu_buf[0] == -1) && (vout->ipu_buf[1] == -1)) {
+ vout->state = STATE_STREAM_OFF;
+ }
}
spin_unlock_irqrestore(&g_lock, lock_flags);
@@ -540,12 +581,15 @@ static irqreturn_t mxc_v4l2out_work_irq_handler(int irq, void *dev_id)
int index;
unsigned long lock_flags = 0;
vout_data *vout = dev_id;
- int pp_out_buf_num = 0;
+ int pp_out_buf_left_right = 0;
int disp_buf_num = 0;
int disp_buf_num_next = 1;
+ int local_buffer = 0;
int pp_out_buf_offset = 0;
+ int pp_out_buf_up_down = 0;
int release_buffer = 0;
- u32 eba_offset;
+ u32 eba_offset = 0;
+ u32 vertical_offset = 0;
u16 x_pos;
u16 y_pos;
int ret = -1;
@@ -563,17 +607,37 @@ static irqreturn_t mxc_v4l2out_work_irq_handler(int irq, void *dev_id)
if (last_buf != -1) {
/* If IC split mode on, update output buffer number */
if (vout->pp_split) {
- pp_out_buf_num = vout->pp_split_buf_num & 1;/* left/right stripe */
- disp_buf_num = vout->pp_split_buf_num >> 1;
- disp_buf_num_next = ((vout->pp_split_buf_num+2) & 3) >> 1;
- if (!pp_out_buf_num) {/* next buffer is right stripe*/
- eba_offset = vout->pp_right_stripe.input_column;/*always right stripe*/
+ pp_out_buf_up_down = vout->pp_split_buf_num & 1;/* left/right stripe */
+ pp_out_buf_left_right = (vout->pp_split_buf_num >> 1) & 1; /* up/down */
+ local_buffer = (vout->pp_split == 1) ? pp_out_buf_up_down :
+ pp_out_buf_left_right;
+ disp_buf_num = vout->pp_split_buf_num >> 2;
+ disp_buf_num_next =
+ ((vout->pp_split_buf_num + (vout->pp_split << 0x1)) & 7) >> 2;
+ if ((!pp_out_buf_left_right) ||
+ ((!pp_out_buf_up_down) && (vout->pp_split == 1))) {
+ if (vout->pp_split == 1) {
+ eba_offset = ((pp_out_buf_left_right + pp_out_buf_up_down) & 1) ?
+ vout->pp_right_stripe.input_column :
+ vout->pp_left_stripe.input_column;
+ vertical_offset = pp_out_buf_up_down ?
+ vout->pp_up_stripe.input_column :
+ vout->pp_down_stripe.input_column;
+
+ } else {
+ eba_offset = pp_out_buf_left_right ?
+ vout->pp_left_stripe.input_column :
+ vout->pp_right_stripe.input_column;
+ vertical_offset = pp_out_buf_left_right ?
+ vout->pp_up_stripe.input_column :
+ vout->pp_down_stripe.input_column;
+ }
+
ret = ipu_update_channel_buffer(vout->post_proc_ch,
IPU_INPUT_BUFFER,
- 1, /* right stripe */
+ (1 - local_buffer),
(vout->v4l2_bufs[vout->ipu_buf[disp_buf_num]].m.offset)
- + eba_offset);
-
+ + eba_offset + vertical_offset * vout->bytesperline);
ret += ipu_update_channel_offset(vout->post_proc_ch,
IPU_INPUT_BUFFER,
vout->v2f.fmt.pix.pixelformat,
@@ -582,68 +646,78 @@ static irqreturn_t mxc_v4l2out_work_irq_handler(int irq, void *dev_id)
vout->bytesperline,
vout->offset.u_offset,
vout->offset.v_offset,
- 0,
- vout->pp_right_stripe.input_column);
+ vertical_offset,
+ eba_offset);
/* select right stripe */
- ret += ipu_select_buffer(vout->post_proc_ch,
- IPU_INPUT_BUFFER, 1);
+ ret += ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER,
+ (1 - local_buffer));
if (ret < 0)
dev_err(&vout->video_dev->dev,
"unable to set IPU buffer ready\n");
+ }
- vout->ipu_buf[vout->next_done_ipu_buf] = -1;
- vout->next_done_ipu_buf = !vout->next_done_ipu_buf;
+ /* offset for next buffer's EBA */
+ eba_offset = 0;
+ if (vout->pp_split == 1) {
+ pp_out_buf_offset = ((vout->pp_split_buf_num >> 1) & 1) ?
+ vout->pp_left_stripe.output_column :
+ vout->pp_right_stripe.output_column;
- } else /* right stripe is done, run display refresh */
- select_display_buffer(vout, disp_buf_num);
+ eba_offset = ((vout->pp_split_buf_num & 1) ?
+ vout->pp_down_stripe.output_column :
+ vout->pp_up_stripe.output_column);
- vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf;
+ } else {
+ pp_out_buf_offset = ((vout->pp_split_buf_num >> 1) & 1) ?
+ vout->pp_right_stripe.output_column :
+ vout->pp_left_stripe.output_column;
+ eba_offset = ((vout->pp_split_buf_num >> 1) & 1) ?
+ vout->pp_down_stripe.output_column :
+ vout->pp_up_stripe.output_column;
+ }
- /* offset for next buffer's EBA */
- pp_out_buf_offset = pp_out_buf_num ? vout->pp_right_stripe.output_column :
- vout->pp_left_stripe.output_column;
- eba_offset = 0;
if (vout->cur_disp_output == 5) {
x_pos = (vout->crop_current.left / 8) * 8;
y_pos = vout->crop_current.top;
- eba_offset = (vout->xres * y_pos + x_pos) * vout->bpp / 8;
+ eba_offset += (vout->xres * y_pos + x_pos) * vout->bpp / 8;
}
+
/* next buffer update */
eba_offset = vout->display_bufs[disp_buf_num_next] +
- pp_out_buf_offset + eba_offset;
+ pp_out_buf_offset + eba_offset;
ipu_update_channel_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER,
- pp_out_buf_num, eba_offset);
+ local_buffer, eba_offset);
/* next buffer ready */
- ret = ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, pp_out_buf_num);
+ ret = ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, local_buffer);
- /* next stripe_buffer index 0..3 */
- vout->pp_split_buf_num = (vout->pp_split_buf_num + 1) & 3;
+ /* next stripe_buffer index 0..7 */
+ vout->pp_split_buf_num = (vout->pp_split_buf_num + vout->pp_split) & 0x7;
} else {
- /* show to display */
- select_display_buffer(vout, vout->next_done_ipu_buf);
+ disp_buf_num = vout->next_done_ipu_buf;
ret += ipu_select_buffer(vout->display_input_ch, IPU_OUTPUT_BUFFER,
vout->next_done_ipu_buf);
}
/* release buffer. For split mode: if second stripe is done */
- release_buffer = vout->pp_split ? pp_out_buf_num : 1;
+ release_buffer = vout->pp_split ? (!(vout->pp_split_buf_num & 0x3)) : 1;
if (release_buffer) {
- if ((!INTERLACED_CONTENT(vout)) || (vout->next_done_ipu_buf)) {
- g_buf_output_cnt++;
- vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE;
- queue_buf(&vout->done_q, last_buf);
- wake_up_interruptible(&vout->v4l_bufq);
- }
+ select_display_buffer(vout, disp_buf_num);
+ g_buf_output_cnt++;
+ vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE;
+ queue_buf(&vout->done_q, last_buf);
+ wake_up_interruptible(&vout->v4l_bufq);
vout->ipu_buf[vout->next_done_ipu_buf] = -1;
if (LOAD_3FIELDS(vout)) {
vout->ipu_buf_p[vout->next_done_ipu_buf] = -1;
vout->ipu_buf_n[vout->next_done_ipu_buf] = -1;
}
- vout->next_done_ipu_buf = !vout->next_done_ipu_buf;
+ /* split mode use buf 0 only, no need switch buf */
+ if (!vout->pp_split)
+ vout->next_done_ipu_buf = !vout->next_done_ipu_buf;
}
} /* end of last_buf != -1 */
@@ -702,7 +776,6 @@ static int init_VDI_channel(vout_data *vout, ipu_channel_params_t params)
static int init_VDI_in_channel_buffer(vout_data *vout, uint32_t in_pixel_fmt,
uint16_t in_width, uint16_t in_height,
uint32_t stride,
- dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
uint32_t u_offset, uint32_t v_offset)
{
struct device *dev = &vout->video_dev->dev;
@@ -710,7 +783,7 @@ static int init_VDI_in_channel_buffer(vout_data *vout, uint32_t in_pixel_fmt,
if (ipu_init_channel_buffer(MEM_VDI_PRP_VF_MEM, IPU_INPUT_BUFFER,
in_pixel_fmt, in_width, in_height, stride,
IPU_ROTATE_NONE,
- vout->v4l2_bufs[vout->ipu_buf[0]].m.offset+vout->bytesperline,
+ vout->v4l2_bufs[vout->ipu_buf[0]].m.offset,
vout->v4l2_bufs[vout->ipu_buf[0]].m.offset,
u_offset, v_offset) != 0) {
dev_err(dev, "Error initializing VDI current input buffer\n");
@@ -721,7 +794,7 @@ static int init_VDI_in_channel_buffer(vout_data *vout, uint32_t in_pixel_fmt,
IPU_INPUT_BUFFER,
in_pixel_fmt, in_width, in_height,
stride, IPU_ROTATE_NONE,
- vout->v4l2_bufs[vout->ipu_buf_p[0]].m.offset,
+ vout->v4l2_bufs[vout->ipu_buf_p[0]].m.offset+vout->bytesperline,
vout->v4l2_bufs[vout->ipu_buf_p[0]].m.offset+vout->bytesperline,
u_offset, v_offset) != 0) {
dev_err(dev, "Error initializing VDI previous input buffer\n");
@@ -731,7 +804,7 @@ static int init_VDI_in_channel_buffer(vout_data *vout, uint32_t in_pixel_fmt,
IPU_INPUT_BUFFER,
in_pixel_fmt, in_width, in_height,
stride, IPU_ROTATE_NONE,
- vout->v4l2_bufs[vout->ipu_buf_n[0]].m.offset,
+ vout->v4l2_bufs[vout->ipu_buf_n[0]].m.offset+vout->bytesperline,
vout->v4l2_bufs[vout->ipu_buf_n[0]].m.offset+vout->bytesperline,
u_offset, v_offset) != 0) {
dev_err(dev, "Error initializing VDI next input buffer\n");
@@ -759,10 +832,7 @@ static int init_VDI(ipu_channel_params_t params, vout_data *vout,
params.mem_prp_vf_mem.in_pixel_fmt = vout->v2f.fmt.pix.pixelformat;
params.mem_prp_vf_mem.out_width = out_width;
params.mem_prp_vf_mem.out_height = out_height;
- if (vout->display_ch == ADC_SYS2)
- params.mem_prp_vf_mem.out_pixel_fmt = SDC_FG_FB_FORMAT;
- else
- params.mem_prp_vf_mem.out_pixel_fmt = bpp_to_fmt(fbi);
+ params.mem_prp_vf_mem.out_pixel_fmt = bpp_to_fmt(fbi);
if (init_VDI_channel(vout, params) != 0) {
dev_err(dev, "Error init_VDI_channel channel\n");
@@ -775,8 +845,6 @@ static int init_VDI(ipu_channel_params_t params, vout_data *vout,
params.mem_prp_vf_mem.in_height,
bytes_per_pixel(params.mem_prp_vf_mem.
in_pixel_fmt),
- vout->v4l2_bufs[vout->ipu_buf[0]].m.offset,
- vout->v4l2_bufs[vout->ipu_buf[1]].m.offset,
vout->offset.u_offset,
vout->offset.v_offset) != 0) {
return -EINVAL;
@@ -805,7 +873,6 @@ static int init_VDI(ipu_channel_params_t params, vout_data *vout,
dev_err(dev, "Error initializing PRP output buffer\n");
return -EINVAL;
}
-
if (ipu_init_channel(MEM_ROT_VF_MEM, NULL) != 0) {
dev_err(dev, "Error initializing PP ROT channel\n");
return -EINVAL;
@@ -883,14 +950,14 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout,
u32 eba_offset;
u16 x_pos;
u16 y_pos;
+ dma_addr_t phy_addr0;
+ dma_addr_t phy_addr1;
+
eba_offset = 0;
x_pos = 0;
y_pos = 0;
- if (vout->display_ch == ADC_SYS2)
- params->mem_pp_mem.out_pixel_fmt = SDC_FG_FB_FORMAT;
- else
- params->mem_pp_mem.out_pixel_fmt = bpp_to_fmt(fbi);
+ params->mem_pp_mem.out_pixel_fmt = bpp_to_fmt(fbi);
if (vout->cur_disp_output == 5) {
x_pos = (vout->crop_current.left / 8) * 8;
@@ -907,37 +974,66 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout,
params->mem_pp_mem.in_pixel_fmt = vout->v2f.fmt.pix.pixelformat;
params->mem_pp_mem.out_width = out_width;
params->mem_pp_mem.out_height = out_height;
- params->mem_pp_mem.out_resize_ratio = 0; /* 0 means unused */
-
+ params->mem_pp_mem.outh_resize_ratio = 0; /* 0 means unused */
+ params->mem_pp_mem.outv_resize_ratio = 0; /* 0 means unused */
/* split IC by two stripes, the by pass is impossible*/
if (vout->pp_split) {
- ipu_calc_stripes_sizes(
- params->mem_pp_mem.in_width, /* input frame width;>1 */
- params->mem_pp_mem.out_width, /* output frame width; >1 */
- ipu_ic_out_max_width_size,
- (((unsigned long long)1) << 32), /* 32bit for fractional*/
- 1, /* equal stripes */
- params->mem_pp_mem.in_pixel_fmt,
- params->mem_pp_mem.out_pixel_fmt,
- &(vout->pp_left_stripe),
- &(vout->pp_right_stripe));
-
- vout->pp_left_stripe.input_column = vout->pp_left_stripe.input_column *
+ vout->pp_left_stripe.input_column = 0;
+ vout->pp_left_stripe.output_column = 0;
+ vout->pp_right_stripe.input_column = 0;
+ vout->pp_right_stripe.output_column = 0;
+ vout->pp_up_stripe.input_column = 0;
+ vout->pp_up_stripe.output_column = 0;
+ vout->pp_down_stripe.input_column = 0;
+ vout->pp_down_stripe.output_column = 0;
+ if (vout->pp_split != 3) {
+ ipu_calc_stripes_sizes(
+ params->mem_pp_mem.in_width, /* input frame width;>1 */
+ params->mem_pp_mem.out_width, /* output frame width; >1 */
+ ipu_ic_out_max_width_size,
+ (((unsigned long long)1) << 32), /* 32bit for fractional*/
+ 1, /* equal stripes */
+ params->mem_pp_mem.in_pixel_fmt,
+ params->mem_pp_mem.out_pixel_fmt,
+ &(vout->pp_left_stripe),
+ &(vout->pp_right_stripe));
+
+ vout->pp_left_stripe.input_column = vout->pp_left_stripe.input_column *
fmt_to_bpp(vout->v2f.fmt.pix.pixelformat) / 8;
- vout->pp_left_stripe.output_column = vout->pp_left_stripe.output_column *
+ vout->pp_left_stripe.output_column = vout->pp_left_stripe.output_column *
fmt_to_bpp(params->mem_pp_mem.out_pixel_fmt) / 8;
- vout->pp_right_stripe.input_column = vout->pp_right_stripe.input_column *
+ vout->pp_right_stripe.input_column = vout->pp_right_stripe.input_column *
fmt_to_bpp(vout->v2f.fmt.pix.pixelformat) / 8;
- vout->pp_right_stripe.output_column = vout->pp_right_stripe.output_column *
+ vout->pp_right_stripe.output_column = vout->pp_right_stripe.output_column *
fmt_to_bpp(params->mem_pp_mem.out_pixel_fmt) / 8;
+
/* updare parameters */
params->mem_pp_mem.in_width = vout->pp_left_stripe.input_width;
params->mem_pp_mem.out_width = vout->pp_left_stripe.output_width;
out_width = vout->pp_left_stripe.output_width;
/* for using in ic_init*/
- params->mem_pp_mem.out_resize_ratio = vout->pp_left_stripe.irr;
-
+ params->mem_pp_mem.outh_resize_ratio = vout->pp_left_stripe.irr;
+ }
+ if (vout->pp_split != 2) {
+ ipu_calc_stripes_sizes(
+ params->mem_pp_mem.in_height, /* input frame width;>1 */
+ params->mem_pp_mem.out_height, /* output frame width; >1 */
+ ipu_ic_out_max_height_size,
+ (((unsigned long long)1) << 32),/* 32bit for fractional */
+ 1, /* equal stripes */
+ params->mem_pp_mem.in_pixel_fmt,
+ params->mem_pp_mem.out_pixel_fmt,
+ &(vout->pp_up_stripe),
+ &(vout->pp_down_stripe));
+ vout->pp_down_stripe.output_column = vout->pp_down_stripe.output_column * out_stride;
+ vout->pp_up_stripe.output_column = vout->pp_up_stripe.output_column * out_stride;
+ params->mem_pp_mem.outv_resize_ratio = vout->pp_up_stripe.irr;
+ params->mem_pp_mem.in_height = vout->pp_up_stripe.input_width;/*height*/
+ out_height = vout->pp_up_stripe.output_width;/*height*/
+ if (vout->pp_split == 3)
+ vout->pp_split = 2;/*2 vertical stripe as two horizontal stripes */
+ }
vout->pp_split_buf_num = 0;
}
@@ -946,6 +1042,12 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout,
return -EINVAL;
}
+ /* always enable double buffer */
+ phy_addr0 = vout->v4l2_bufs[vout->ipu_buf[0]].m.offset;
+ if (vout->ipu_buf[1] == -1)
+ phy_addr1 = phy_addr0;
+ else
+ phy_addr1 = vout->v4l2_bufs[vout->ipu_buf[1]].m.offset;
if (ipu_init_channel_buffer(vout->post_proc_ch,
IPU_INPUT_BUFFER,
params->mem_pp_mem.in_pixel_fmt,
@@ -955,8 +1057,8 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout,
bytes_per_pixel(params->mem_pp_mem.
in_pixel_fmt),
IPU_ROTATE_NONE,
- vout->v4l2_bufs[vout->ipu_buf[0]].m.offset,
- vout->v4l2_bufs[vout->ipu_buf[1]].m.offset,
+ phy_addr0,
+ phy_addr1,
vout->offset.u_offset,
vout->offset.v_offset) != 0) {
dev_err(dev, "Error initializing PP input buffer\n");
@@ -1048,20 +1150,27 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout,
ipu_update_channel_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER,
0,
vout->v4l2_bufs[vout->ipu_buf[0]].m.offset +
- vout->pp_left_stripe.input_column);
+ vout->pp_left_stripe.input_column +
+ vout->pp_up_stripe.input_column * vout->bytesperline);
+
+
ipu_update_channel_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER,
1,
vout->v4l2_bufs[vout->ipu_buf[0]].m.offset +
- vout->pp_right_stripe.input_column);
+ vout->pp_right_stripe.input_column +
+ vout->pp_up_stripe.input_column * vout->bytesperline);
+
ipu_update_channel_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER,
0,
vout->display_bufs[0] + eba_offset +
- vout->pp_left_stripe.output_column);
+ vout->pp_left_stripe.output_column +
+ vout->pp_up_stripe.output_column);
ipu_update_channel_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER,
1,
vout->display_bufs[0] + eba_offset +
- vout->pp_right_stripe.output_column);
+ vout->pp_right_stripe.output_column +
+ vout->pp_up_stripe.output_column);
}
return 0;
@@ -1084,8 +1193,8 @@ static int mxc_v4l2out_streamon(vout_data * vout)
registered_fb[vout->output_fb_num[vout->cur_disp_output]];
u16 out_width;
u16 out_height;
- bool use_direct_adc = false;
mm_segment_t old_fs;
+ unsigned int ipu_ch = CHAN_NONE;
int rc = 0;
dev_dbg(dev, "mxc_v4l2out_streamon: field format=%d\n",
@@ -1107,241 +1216,132 @@ static int mxc_v4l2out_streamon(vout_data * vout)
return -EINVAL;
}
+ /*
+ * params init, check whether operation exceed the IC limitation:
+ * whether split mode used ( ipu version >= ipuv3 only)
+ */
g_irq_cnt = g_buf_output_cnt = g_buf_q_cnt = g_buf_dq_cnt = 0;
out_width = vout->crop_current.width;
out_height = vout->crop_current.height;
+ vout->disp_buf_num = 0;
vout->next_done_ipu_buf = 0;
- vout->next_rdy_ipu_buf = 1;
+ vout->next_rdy_ipu_buf = vout->next_disp_ipu_buf = 1;
+ vout->fb_blank = 0;
vout->pp_split = 0;
-
- if (!INTERLACED_CONTENT(vout)) {
- vout->next_done_ipu_buf = vout->next_rdy_ipu_buf = 0;
- vout->ipu_buf[0] = dequeue_buf(&vout->ready_q);
+ ipu_ic_out_max_height_size = 1024;
#ifdef CONFIG_MXC_IPU_V1
+ if (cpu_is_mx35())
ipu_ic_out_max_width_size = 800;
+ else
+ ipu_ic_out_max_width_size = 720;
#else
- ipu_ic_out_max_width_size = 1024;
+ ipu_ic_out_max_width_size = 1024;
#endif
+ if ((out_width > ipu_ic_out_max_width_size) ||
+ (out_height > ipu_ic_out_max_height_size))
+ vout->pp_split = 4;
+ if (!INTERLACED_CONTENT(vout)) {
+ vout->ipu_buf[0] = dequeue_buf(&vout->ready_q);
/* split IC by two stripes, the by pass is impossible*/
if ((out_width != vout->v2f.fmt.pix.width ||
out_height != vout->v2f.fmt.pix.height) &&
- out_width > ipu_ic_out_max_width_size) {
- vout->pp_split = 1;
+ vout->pp_split) {
+ vout->next_done_ipu_buf = vout->next_rdy_ipu_buf = 0;
vout->ipu_buf[1] = vout->ipu_buf[0];
vout->frame_count = 1;
+ if ((out_width > ipu_ic_out_max_width_size) &&
+ (out_height > ipu_ic_out_max_height_size))
+ vout->pp_split = 1; /*4 stripes*/
+ else if (!(out_height > ipu_ic_out_max_height_size))
+ vout->pp_split = 2; /*two horizontal stripes */
+ else
+ vout->pp_split = 3; /*2 vertical stripes*/
} else {
- vout->ipu_buf[1] = dequeue_buf(&vout->ready_q);
- vout->frame_count = 2;
+ vout->ipu_buf[1] = -1;
+ vout->frame_count = 1;
}
} else if (!LOAD_3FIELDS(vout)) {
vout->ipu_buf[0] = dequeue_buf(&vout->ready_q);
vout->ipu_buf[1] = -1;
vout->frame_count = 1;
- last_index_n = vout->ipu_buf[0];
} else {
vout->ipu_buf_p[0] = dequeue_buf(&vout->ready_q);
- vout->ipu_buf[0] = vout->ipu_buf_p[0];
- vout->ipu_buf_n[0] = dequeue_buf(&vout->ready_q);
+ vout->ipu_buf[0] = dequeue_buf(&vout->ready_q);
+ vout->ipu_buf_n[0] = vout->ipu_buf[0];
vout->ipu_buf_p[1] = -1;
vout->ipu_buf[1] = -1;
vout->ipu_buf_n[1] = -1;
- last_index_c = vout->ipu_buf[0];
last_index_n = vout->ipu_buf_n[0];
vout->frame_count = 2;
}
- /* Init Display Channel */
-#ifdef CONFIG_FB_MXC_ASYNC_PANEL
- if (vout->cur_disp_output < DISP3) {
- vout->work_irq = IPU_IRQ_PP_IN_EOF;
- ipu_clear_irq(vout->work_irq);
- ipu_request_irq(vout->work_irq,
- mxc_v4l2out_work_irq_handler,
- 0, vout->video_dev->name, vout);
- mxcfb_set_refresh_mode(fbi, MXCFB_REFRESH_OFF, 0);
- fbi = NULL;
- if (ipu_can_rotate_in_place(vout->rotate)) {
- dev_dbg(dev, "Using PP direct to ADC channel\n");
- use_direct_adc = true;
- vout->display_ch = MEM_PP_ADC;
- vout->post_proc_ch = MEM_PP_ADC;
-
- memset(&params, 0, sizeof(params));
- params.mem_pp_adc.in_width = vout->v2f.fmt.pix.width;
- params.mem_pp_adc.in_height = vout->v2f.fmt.pix.height;
- params.mem_pp_adc.in_pixel_fmt =
- vout->v2f.fmt.pix.pixelformat;
- params.mem_pp_adc.out_width = out_width;
- params.mem_pp_adc.out_height = out_height;
- params.mem_pp_adc.out_pixel_fmt = SDC_FG_FB_FORMAT;
-#ifdef CONFIG_FB_MXC_EPSON_PANEL
- params.mem_pp_adc.out_left =
- 2 + vout->crop_current.left;
-#else
- params.mem_pp_adc.out_left =
- 12 + vout->crop_current.left;
-#endif
- params.mem_pp_adc.out_top = vout->crop_current.top;
- if (ipu_init_channel(vout->post_proc_ch, &params) != 0) {
- dev_err(dev, "Error initializing PP chan\n");
- return -EINVAL;
- }
- if (ipu_init_channel_buffer(vout->post_proc_ch,
- IPU_INPUT_BUFFER,
- params.mem_pp_adc.
- in_pixel_fmt,
- params.mem_pp_adc.in_width,
- params.mem_pp_adc.in_height,
- vout->v2f.fmt.pix.
- bytesperline /
- bytes_per_pixel(params.
- mem_pp_adc.
- in_pixel_fmt),
- vout->rotate,
- vout->v4l2_bufs[vout->ipu_buf[0]].m.offset,
- vout->v4l2_bufs[vout->ipu_buf[1]].m.offset,
- vout->offset.u_offset,
- vout->offset.v_offset) !=
- 0) {
- dev_err(dev, "Error initializing PP in buf\n");
- return -EINVAL;
- }
-
- if (ipu_init_channel_buffer(vout->post_proc_ch,
- IPU_OUTPUT_BUFFER,
- params.mem_pp_adc.
- out_pixel_fmt, out_width,
- out_height, out_width,
- vout->rotate, 0, 0, 0,
- 0) != 0) {
- dev_err(dev,
- "Error initializing PP output buffer\n");
- return -EINVAL;
- }
-
- } else {
- dev_dbg(dev, "Using ADC SYS2 channel\n");
- vout->display_ch = ADC_SYS2;
- vout->post_proc_ch = MEM_PP_MEM;
-
- if (vout->display_bufs[0]) {
- mxc_free_buffers(vout->display_bufs,
- vout->display_bufs_vaddr,
- 2, vout->display_buf_size);
- }
-
- vout->display_buf_size = vout->crop_current.width *
- vout->crop_current.height *
- fmt_to_bpp(SDC_FG_FB_FORMAT) / 8;
- mxc_allocate_buffers(vout->display_bufs,
- vout->display_bufs_vaddr,
- 2, vout->display_buf_size);
-
- memset(&params, 0, sizeof(params));
- params.adc_sys2.disp = vout->cur_disp_output;
- params.adc_sys2.ch_mode = WriteTemplateNonSeq;
-#ifdef CONFIG_FB_MXC_EPSON_PANEL
- params.adc_sys2.out_left = 2 + vout->crop_current.left;
-#else
- params.adc_sys2.out_left = 12 + vout->crop_current.left;
-#endif
- params.adc_sys2.out_top = vout->crop_current.top;
- if (ipu_init_channel(ADC_SYS2, &params) < 0)
- return -EINVAL;
-
- if (ipu_init_channel_buffer(vout->display_ch,
- IPU_INPUT_BUFFER,
- SDC_FG_FB_FORMAT,
- out_width, out_height,
- out_width, IPU_ROTATE_NONE,
- vout->display_bufs[0],
- vout->display_bufs[1], 0,
- 0) != 0) {
- dev_err(dev,
- "Error initializing SDC FG buffer\n");
- return -EINVAL;
- }
- }
- } else
-#endif
- { /* Use SDC */
- unsigned int ipu_ch = CHAN_NONE;
-
- dev_dbg(dev, "Using SDC channel\n");
-
- if (INTERLACED_CONTENT(vout))
- vout->work_irq = IPU_IRQ_PRP_VF_OUT_EOF;
- else
- vout->work_irq = IPU_IRQ_PP_IN_EOF;
-
- /*
- * Bypass IC if resizing and rotation are not needed
- * Meanwhile, apply IC bypass to SDC only
- */
- fbvar = fbi->var;
- vout->xres = fbvar.xres;
- vout->yres = fbvar.yres;
-
- if (vout->cur_disp_output == 3 || vout->cur_disp_output == 5) {
- fbvar.bits_per_pixel = 16;
+ /*
+ * Bypass IC if resizing and rotation are not needed
+ * Meanwhile, apply IC bypass to SDC only
+ */
+ fbvar = fbi->var;
+ vout->xres = fbvar.xres;
+ vout->yres = fbvar.yres;
+
+ if (vout->cur_disp_output == 3 || vout->cur_disp_output == 5) {
+ fbvar.bits_per_pixel = 16;
+ if (vout->cur_disp_output == 3) {
+ /* Only set YUV for the first display. The second display can
+ * only work in RGB */
if (format_is_yuv(vout->v2f.fmt.pix.pixelformat))
fbvar.nonstd = IPU_PIX_FMT_UYVY;
else
fbvar.nonstd = 0;
- if (vout->cur_disp_output == 3) {
- fbvar.xres = out_width;
- fbvar.yres = out_height;
- vout->xres = fbvar.xres;
- vout->yres = fbvar.yres;
- }
- fbvar.xres_virtual = fbvar.xres;
- fbvar.yres_virtual = fbvar.yres * 2;
+ fbvar.xres = out_width;
+ fbvar.yres = out_height;
+ vout->xres = fbvar.xres;
+ vout->yres = fbvar.yres;
}
- if (out_width == vout->v2f.fmt.pix.width &&
- out_height == vout->v2f.fmt.pix.height &&
- vout->xres == out_width &&
- vout->yres == out_height &&
- ipu_can_rotate_in_place(vout->rotate)) {
- vout->ic_bypass = 1;
- } else {
- vout->ic_bypass = 0;
- }
+ fbvar.xres_virtual = fbvar.xres;
+ fbvar.yres_virtual = fbvar.yres * 2;
+ }
+
+ if (out_width == vout->v2f.fmt.pix.width &&
+ out_height == vout->v2f.fmt.pix.height &&
+ vout->xres == out_width &&
+ vout->yres == out_height &&
+ ipu_can_rotate_in_place(vout->rotate) &&
+ (vout->bytesperline ==
+ bytes_per_pixel(vout->v2f.fmt.pix.pixelformat) * out_width) &&
+ !INTERLACED_CONTENT(vout)) {
+ vout->ic_bypass = 1;
+ } else {
+ vout->ic_bypass = 0;
+ }
#ifdef CONFIG_MXC_IPU_V1
- /* IPUv1 needs IC to do CSC */
- if (format_is_yuv(vout->v2f.fmt.pix.pixelformat) !=
- format_is_yuv(bpp_to_fmt(fbi)))
- vout->ic_bypass = 0;
+ /* IPUv1 needs IC to do CSC */
+ if (format_is_yuv(vout->v2f.fmt.pix.pixelformat) !=
+ format_is_yuv(bpp_to_fmt(fbi)))
+ vout->ic_bypass = 0;
#endif
- /* We are using IC to do input cropping */
- if (vout->queue_buf_paddr[vout->ipu_buf[0]] !=
- vout->v4l2_bufs[vout->ipu_buf[0]].m.offset ||
- vout->queue_buf_paddr[vout->ipu_buf[1]] !=
- vout->v4l2_bufs[vout->ipu_buf[1]].m.offset)
- vout->ic_bypass = 0;
-
- if (fbi->fbops->fb_ioctl) {
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_IPU_CHAN,
- (unsigned long)&ipu_ch);
- set_fs(old_fs);
- }
+ if (fbi->fbops->fb_ioctl) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_IPU_CHAN,
+ (unsigned long)&ipu_ch);
+ set_fs(old_fs);
+ }
- if (ipu_ch == CHAN_NONE) {
- dev_err(dev, "Can not get display ipu channel\n");
- return -EINVAL;
- }
+ if (ipu_ch == CHAN_NONE) {
+ dev_err(dev, "Can not get display ipu channel\n");
+ return -EINVAL;
+ }
- vout->display_ch = ipu_ch;
+ vout->display_ch = ipu_ch;
- if (vout->ic_bypass) {
- pr_debug("Bypassing IC\n");
- vout->work_irq = -1;
- switch (vout->v2f.fmt.pix.pixelformat) {
+ if (vout->ic_bypass) {
+ pr_debug("Bypassing IC\n");
+ vout->pp_split = 0;
+ switch (vout->v2f.fmt.pix.pixelformat) {
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_NV12:
@@ -1353,87 +1353,80 @@ static int mxc_v4l2out_streamon(vout_data * vout)
default:
fbvar.bits_per_pixel = 8*
bytes_per_pixel(vout->v2f.fmt.pix.pixelformat);
- }
- fbvar.nonstd = vout->v2f.fmt.pix.pixelformat;
}
+ fbvar.nonstd = vout->v2f.fmt.pix.pixelformat;
+ }
- fbvar.activate |= FB_ACTIVATE_FORCE;
- fb_set_var(fbi, &fbvar);
+ /* Init display channel through fb API */
+ fbvar.activate |= FB_ACTIVATE_FORCE;
+ fb_set_var(fbi, &fbvar);
- if (fbi->fbops->fb_ioctl && vout->display_ch == MEM_FG_SYNC) {
- fb_pos.x = vout->crop_current.left;
- fb_pos.y = vout->crop_current.top;
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- fbi->fbops->fb_ioctl(fbi, MXCFB_SET_OVERLAY_POS,
- (unsigned long)&fb_pos);
- set_fs(old_fs);
- }
+ if (fbi->fbops->fb_ioctl && vout->display_ch == MEM_FG_SYNC) {
+ fb_pos.x = vout->crop_current.left;
+ fb_pos.y = vout->crop_current.top;
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ fbi->fbops->fb_ioctl(fbi, MXCFB_SET_OVERLAY_POS,
+ (unsigned long)&fb_pos);
+ set_fs(old_fs);
+ }
+
+ vout->display_bufs[1] = fbi->fix.smem_start;
+ vout->display_bufs[0] = fbi->fix.smem_start +
+ (fbi->fix.line_length * vout->yres);
+ vout->display_buf_size = vout->xres *
+ vout->yres * fbi->var.bits_per_pixel / 8;
+
+ /* fill black color for init fb, we assume fb has double buffer*/
+ if (format_is_yuv(vout->v2f.fmt.pix.pixelformat)) {
+ int i;
- vout->display_bufs[1] = fbi->fix.smem_start;
- vout->display_bufs[0] = fbi->fix.smem_start +
- (fbi->fix.line_length * vout->yres);
- vout->display_buf_size = vout->xres *
- vout->yres * fbi->var.bits_per_pixel / 8;
-
- /* fill black color for init fb, we assume fb has double buffer*/
- if (format_is_yuv(vout->v2f.fmt.pix.pixelformat)) {
- int i;
-
- if ((vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) ||
- (vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) ||
- (!vout->ic_bypass)) {
- short * tmp = (short *) fbi->screen_base;
- short color;
- if (vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
- color = 0x8000;
- else
- color = 0x80;
- for (i = 0; i < (fbi->fix.line_length * fbi->var.yres_virtual)/2;
+ if ((vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) ||
+ (vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) ||
+ (!vout->ic_bypass)) {
+ short * tmp = (short *) fbi->screen_base;
+ short color;
+ if (vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
+ color = 0x8000;
+ else
+ color = 0x80;
+ for (i = 0; i < (fbi->fix.line_length * fbi->var.yres_virtual)/2;
i++, tmp++)
- *tmp = color;
- } else if ((vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) ||
+ *tmp = color;
+ } else if ((vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) ||
(vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) ||
(vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12)) {
- char * base = (char *)fbi->screen_base;
- int j, screen_size = fbi->var.xres * fbi->var.yres;
-
- for (j = 0; j < 2; j++) {
- memset(base, 0, screen_size);
- base += screen_size;
- for (i = 0; i < screen_size/2; i++, base++)
- *base = 0x80;
- }
- } else if (vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) {
- char * base = (char *)fbi->screen_base;
- int j, screen_size = fbi->var.xres * fbi->var.yres;
-
- for (j = 0; j < 2; j++) {
- memset(base, 0, screen_size);
- base += screen_size;
- for (i = 0; i < screen_size; i++, base++)
- *base = 0x80;
- }
+ char * base = (char *)fbi->screen_base;
+ int j, screen_size = fbi->var.xres * fbi->var.yres;
+
+ for (j = 0; j < 2; j++) {
+ memset(base, 0, screen_size);
+ base += screen_size;
+ for (i = 0; i < screen_size/2; i++, base++)
+ *base = 0x80;
+ }
+ } else if (vout->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) {
+ char * base = (char *)fbi->screen_base;
+ int j, screen_size = fbi->var.xres * fbi->var.yres;
+
+ for (j = 0; j < 2; j++) {
+ memset(base, 0, screen_size);
+ base += screen_size;
+ for (i = 0; i < screen_size; i++, base++)
+ *base = 0x80;
}
- } else
- memset(fbi->screen_base, 0x0,
- fbi->fix.line_length * fbi->var.yres_virtual);
-
- if (INTERLACED_CONTENT(vout))
- vout->post_proc_ch = MEM_VDI_PRP_VF_MEM;
- else
- vout->post_proc_ch = MEM_PP_MEM;
-
- if (!vout->ic_bypass) {
- ipu_clear_irq(vout->work_irq);
- ipu_request_irq(vout->work_irq,
- mxc_v4l2out_work_irq_handler,
- 0, vout->video_dev->name, vout);
}
- }
+ } else
+ memset(fbi->screen_base, 0x0,
+ fbi->fix.line_length * fbi->var.yres_virtual);
+
+ if (INTERLACED_CONTENT(vout))
+ vout->post_proc_ch = MEM_VDI_PRP_VF_MEM;
+ else if (!vout->ic_bypass)
+ vout->post_proc_ch = MEM_PP_MEM;
- /* Init PP */
- if (use_direct_adc == false && !vout->ic_bypass) {
+ /* Init IC channel */
+ if (!vout->ic_bypass) {
if (vout->rotate >= IPU_ROTATE_90_RIGHT) {
out_width = vout->crop_current.height;
out_height = vout->crop_current.width;
@@ -1441,7 +1434,11 @@ static int mxc_v4l2out_streamon(vout_data * vout)
vout->display_input_ch = vout->post_proc_ch;
memset(&params, 0, sizeof(params));
if (INTERLACED_CONTENT(vout)) {
- rc = init_VDI(params, vout, dev, fbi, out_width, out_height);
+ if (vout->pp_split) {
+ dev_err(&vout->video_dev->dev, "VDI split has not supported yet.\n");
+ return -1;
+ } else
+ rc = init_VDI(params, vout, dev, fbi, out_width, out_height);
} else {
rc = init_PP(&params, vout, dev, fbi, out_width, out_height);
}
@@ -1449,52 +1446,79 @@ static int mxc_v4l2out_streamon(vout_data * vout)
return rc;
}
+ if (!vout->ic_bypass) {
+ switch (vout->display_input_ch) {
+ case MEM_PP_MEM:
+ vout->work_irq = IPU_IRQ_PP_OUT_EOF;
+ break;
+ case MEM_VDI_PRP_VF_MEM:
+ vout->work_irq = IPU_IRQ_PRP_VF_OUT_EOF;
+ break;
+ case MEM_ROT_VF_MEM:
+ vout->work_irq = IPU_IRQ_PRP_VF_ROT_OUT_EOF;
+ break;
+ case MEM_ROT_PP_MEM:
+ vout->work_irq = IPU_IRQ_PP_ROT_OUT_EOF;
+ break;
+ default:
+ dev_err(&vout->video_dev->dev,
+ "not support channel, should not be here\n");
+ }
+ } else
+ vout->work_irq = -1;
+
+ if (!vout->ic_bypass && (vout->work_irq > 0)) {
+ ipu_clear_irq(vout->work_irq);
+ ipu_request_irq(vout->work_irq,
+ mxc_v4l2out_work_irq_handler,
+ 0, vout->video_dev->name, vout);
+ }
+
vout->state = STATE_STREAM_PAUSED;
- if (use_direct_adc == false) {
- if (fbi) {
- acquire_console_sem();
- fb_blank(fbi, FB_BLANK_UNBLANK);
- release_console_sem();
- } else {
- ipu_enable_channel(vout->display_ch);
- }
- if (!vout->ic_bypass) {
+ /* Enable display and IC channels */
+ if (fbi) {
+ acquire_console_sem();
+ fb_blank(fbi, FB_BLANK_UNBLANK);
+ release_console_sem();
+ } else {
+ ipu_enable_channel(vout->display_ch);
+ }
+ if (!vout->ic_bypass) {
#ifndef CONFIG_MXC_IPU_V1
- ipu_enable_channel(vout->post_proc_ch);
+ ipu_enable_channel(vout->post_proc_ch);
#endif
- if (LOAD_3FIELDS(vout)) {
- ipu_enable_channel(MEM_VDI_PRP_VF_MEM_P);
- ipu_enable_channel(MEM_VDI_PRP_VF_MEM_N);
- ipu_select_multi_vdi_buffer(0);
- } else if (INTERLACED_CONTENT(vout)) {
- ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0);
- } else {
- ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0);
- if (!vout->pp_split)
- ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 1);
- }
- ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 0);
- ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 1);
+ if (LOAD_3FIELDS(vout)) {
+ ipu_enable_channel(MEM_VDI_PRP_VF_MEM_P);
+ ipu_enable_channel(MEM_VDI_PRP_VF_MEM_N);
+ ipu_select_multi_vdi_buffer(0);
+ } else
+ ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0);
+ ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 0);
+ ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 1);
#ifdef CONFIG_MXC_IPU_V1
- ipu_enable_channel(vout->post_proc_ch);
+ ipu_enable_channel(vout->post_proc_ch);
#endif
- } else {
- ipu_update_channel_buffer(vout->display_ch,
+ } else {
+ ipu_update_channel_buffer(vout->display_ch,
IPU_INPUT_BUFFER,
0, vout->v4l2_bufs[vout->ipu_buf[0]].m.offset);
- ipu_update_channel_buffer(vout->display_ch,
- IPU_INPUT_BUFFER,
- 1, vout->v4l2_bufs[vout->ipu_buf[1]].m.offset);
- ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER, 0);
- ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER, 1);
- queue_work(vout->v4l_wq, &vout->timer_work);
- }
- } else {
- ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0);
- ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 1);
- ipu_enable_channel(vout->post_proc_ch);
+ if (vout->offset.u_offset || vout->offset.v_offset)
+ /* only update u/v offset */
+ ipu_update_channel_offset(vout->display_ch,
+ IPU_INPUT_BUFFER,
+ vout->v2f.fmt.pix.pixelformat,
+ vout->v2f.fmt.pix.width,
+ vout->v2f.fmt.pix.height,
+ vout->bytesperline,
+ vout->offset.u_offset,
+ vout->offset.v_offset,
+ 0,
+ 0);
+ ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER, 0);
+ queue_work(vout->v4l_wq, &vout->icbypass_work);
}
+
vout->start_jiffies = jiffies;
msleep(1);
@@ -1529,7 +1553,8 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
if (!vout->ic_bypass)
ipu_free_irq(vout->work_irq, vout);
- cancel_work_sync(&vout->timer_work);
+ if (vout->ic_bypass)
+ cancel_work_sync(&vout->icbypass_work);
spin_lock_irqsave(&g_lock, lockflag);
@@ -1556,9 +1581,21 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
}
}
- if (vout->post_proc_ch == MEM_PP_MEM ||
+ if (vout->ic_bypass) {
+ fbi->var.activate |= FB_ACTIVATE_FORCE;
+ fb_set_var(fbi, &fbi->var);
+
+ if (vout->display_ch == MEM_FG_SYNC) {
+ acquire_console_sem();
+ fb_blank(fbi, FB_BLANK_POWERDOWN);
+ release_console_sem();
+ }
+
+ vout->display_bufs[0] = 0;
+ vout->display_bufs[1] = 0;
+ } else if (vout->post_proc_ch == MEM_PP_MEM ||
vout->post_proc_ch == MEM_PRP_VF_MEM) {
- /* SDC or ADC with Rotation */
+ /* SDC with Rotation */
if (!ipu_can_rotate_in_place(vout->rotate)) {
ipu_unlink_channels(MEM_PP_MEM, MEM_ROT_PP_MEM);
ipu_disable_channel(MEM_ROT_PP_MEM, true);
@@ -1571,28 +1608,23 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
}
ipu_disable_channel(MEM_PP_MEM, true);
- if (vout->display_ch == ADC_SYS2 ||
- vout->display_ch == MEM_FG_SYNC) {
- ipu_disable_channel(vout->display_ch, true);
- ipu_uninit_channel(vout->display_ch);
- } else {
- fbi->var.activate |= FB_ACTIVATE_FORCE;
- fb_set_var(fbi, &fbi->var);
+ fbi->var.activate |= FB_ACTIVATE_FORCE;
+ fb_set_var(fbi, &fbi->var);
- if (vout->display_ch == MEM_FG_SYNC) {
- acquire_console_sem();
- fb_blank(fbi, FB_BLANK_POWERDOWN);
- release_console_sem();
- }
-
- vout->display_bufs[0] = 0;
- vout->display_bufs[1] = 0;
+ if (vout->display_ch == MEM_FG_SYNC) {
+ acquire_console_sem();
+ fb_blank(fbi, FB_BLANK_POWERDOWN);
+ release_console_sem();
}
+ vout->display_bufs[0] = 0;
+ vout->display_bufs[1] = 0;
+
ipu_uninit_channel(MEM_PP_MEM);
if (!ipu_can_rotate_in_place(vout->rotate))
ipu_uninit_channel(MEM_ROT_PP_MEM);
- } else if (INTERLACED_CONTENT(vout) && (vout->post_proc_ch == MEM_VDI_PRP_VF_MEM)) {
+ } else if (INTERLACED_CONTENT(vout) &&
+ (vout->post_proc_ch == MEM_VDI_PRP_VF_MEM)) {
if (!ipu_can_rotate_in_place(vout->rotate)) {
ipu_unlink_channels(MEM_VDI_PRP_VF_MEM,
MEM_ROT_VF_MEM);
@@ -1606,32 +1638,32 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
}
ipu_disable_channel(MEM_VDI_PRP_VF_MEM, true);
+ if (LOAD_3FIELDS(vout)) {
+ ipu_disable_channel(MEM_VDI_PRP_VF_MEM_P, true);
+ ipu_disable_channel(MEM_VDI_PRP_VF_MEM_N, true);
+ }
- if (vout->display_ch == ADC_SYS2 ||
- vout->display_ch == MEM_FG_SYNC) {
- ipu_disable_channel(vout->display_ch, true);
- ipu_uninit_channel(vout->display_ch);
- } else {
- fbi->var.activate |= FB_ACTIVATE_FORCE;
- fb_set_var(fbi, &fbi->var);
+ fbi->var.activate |= FB_ACTIVATE_FORCE;
+ fb_set_var(fbi, &fbi->var);
- if (vout->display_ch == MEM_FG_SYNC) {
- acquire_console_sem();
- fb_blank(fbi, FB_BLANK_POWERDOWN);
- release_console_sem();
- }
-
- vout->display_bufs[0] = 0;
- vout->display_bufs[1] = 0;
+ if (vout->display_ch == MEM_FG_SYNC) {
+ acquire_console_sem();
+ fb_blank(fbi, FB_BLANK_POWERDOWN);
+ release_console_sem();
}
+ vout->display_bufs[0] = 0;
+ vout->display_bufs[1] = 0;
+
ipu_uninit_channel(MEM_VDI_PRP_VF_MEM);
+ if (LOAD_3FIELDS(vout)) {
+ ipu_uninit_channel(MEM_VDI_PRP_VF_MEM_P);
+ ipu_uninit_channel(MEM_VDI_PRP_VF_MEM_N);
+ }
if (!ipu_can_rotate_in_place(vout->rotate))
ipu_uninit_channel(MEM_ROT_VF_MEM);
- } else { /* ADC Direct */
- ipu_disable_channel(MEM_PP_ADC, true);
- ipu_uninit_channel(MEM_PP_ADC);
}
+
vout->ready_q.head = vout->ready_q.tail = 0;
vout->done_q.head = vout->done_q.tail = 0;
for (i = 0; i < vout->buffer_cnt; i++) {
@@ -1640,23 +1672,9 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
vout->v4l2_bufs[i].timestamp.tv_usec = 0;
}
+ vout->post_proc_ch = CHAN_NONE;
vout->state = STATE_STREAM_OFF;
-#ifdef CONFIG_FB_MXC_ASYNC_PANEL
- if (vout->cur_disp_output < DISP3) {
- if (vout->display_bufs[0] != 0) {
- mxc_free_buffers(vout->display_bufs,
- vout->display_bufs_vaddr, 2,
- vout->display_buf_size);
- }
-
- mxcfb_set_refresh_mode(registered_fb
- [vout->
- output_fb_num[vout->cur_disp_output]],
- MXCFB_REFRESH_PARTIAL, 0);
- }
-#endif
-
return retval;
}
@@ -1751,7 +1769,6 @@ static int mxc_v4l2out_s_fmt(vout_data * vout, struct v4l2_format *f)
dev_err(&vout->video_dev->dev,
"De-interlacing not supported in this device!\n");
vout->field_fmt = V4L2_FIELD_NONE;
- break;
case V4L2_FIELD_INTERLACED_BT:
dev_err(&vout->video_dev->dev,
"V4L2_FIELD_INTERLACED_BT field format not supported yet!\n");
@@ -1898,7 +1915,7 @@ static int mxc_v4l2out_open(struct file *file)
goto oops;
}
- INIT_WORK(&vout->timer_work, timer_work_func);
+ INIT_WORK(&vout->icbypass_work, icbypass_work_func);
}
file->private_data = dev;
@@ -2284,12 +2301,8 @@ mxc_v4l2out_do_ioctl(struct file *file,
break;
}
- if (output->index < 3) {
- *output = mxc_outputs[MXC_V4L2_OUT_2_ADC];
- output->name[4] = '0' + output->index;
- } else {
+ if (output->index >= 3)
*output = mxc_outputs[MXC_V4L2_OUT_2_SDC];
- }
break;
}
case VIDIOC_G_OUTPUT:
diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.h b/drivers/media/video/mxc/output/mxc_v4l2_output.h
index 0dd8eb0076a9..c26194f5ff90 100644
--- a/drivers/media/video/mxc/output/mxc_v4l2_output.h
+++ b/drivers/media/video/mxc/output/mxc_v4l2_output.h
@@ -39,7 +39,6 @@
#define MXC_V4L2_OUT_NUM_OUTPUTS 6
#define MXC_V4L2_OUT_2_SDC 0
-#define MXC_V4L2_OUT_2_ADC 1
typedef struct {
@@ -80,7 +79,9 @@ typedef struct _vout_data {
struct timer_list output_timer;
struct workqueue_struct *v4l_wq;
- struct work_struct timer_work;
+ struct work_struct icbypass_work;
+ int disp_buf_num;
+ int fb_blank;
unsigned long start_jiffies;
u32 frame_count;
@@ -89,6 +90,7 @@ typedef struct _vout_data {
s8 next_rdy_ipu_buf;
s8 next_done_ipu_buf;
+ s8 next_disp_ipu_buf;
s8 ipu_buf[2];
s8 ipu_buf_p[2];
s8 ipu_buf_n[2];
@@ -141,8 +143,10 @@ typedef struct _vout_data {
int pp_split; /* 0,1 */
struct stripe_param pp_left_stripe;
struct stripe_param pp_right_stripe; /* struct for split parameters */
- /* IC ouput buffer number. Counting from 0 to 3 */
- int pp_split_buf_num; /* 0..3 */
+ struct stripe_param pp_up_stripe;
+ struct stripe_param pp_down_stripe;
+ /* IC ouput buffer number. Counting from 0 to 7 */
+ int pp_split_buf_num; /* 0..7 */
u16 bpp ; /* bit per pixel */
u16 xres; /* width of physical frame (BGs) */
u16 yres; /* heigth of physical frame (BGs)*/
diff --git a/drivers/media/video/mxs_pxp.c b/drivers/media/video/mxs_pxp.c
index 83c9c52c3b0c..017d22458a22 100644
--- a/drivers/media/video/mxs_pxp.c
+++ b/drivers/media/video/mxs_pxp.c
@@ -31,6 +31,7 @@
#include <linux/platform_device.h>
#include <linux/vmalloc.h>
#include <linux/videodev2.h>
+#include <linux/delay.h>
#include <media/videobuf-dma-contig.h>
#include <media/v4l2-common.h>
@@ -671,6 +672,7 @@ static int pxp_streamon(struct file *file, void *priv, enum v4l2_buf_type t)
pxp_set_outbuf(pxp);
ret = videobuf_streamon(&pxp->s0_vbq);
+ msleep(20);
if (!ret && (pxp->output == 0))
mxsfb_cfg_pxp(1, pxp->outb_phys);
@@ -686,7 +688,9 @@ static int pxp_streamoff(struct file *file, void *priv, enum v4l2_buf_type t)
if ((t != V4L2_BUF_TYPE_VIDEO_OUTPUT))
return -EINVAL;
+ cancel_work_sync(&pxp->work);
ret = videobuf_streamoff(&pxp->s0_vbq);
+ msleep(20);
if (!ret)
mxsfb_cfg_pxp(0, 0);
@@ -1101,8 +1105,10 @@ static int pxp_close(struct file *file)
{
struct pxps *pxp = video_get_drvdata(video_devdata(file));
- if (pxp->workqueue)
+ if (pxp->workqueue) {
+ flush_workqueue(pxp->workqueue);
destroy_workqueue(pxp->workqueue);
+ }
videobuf_stop(&pxp->s0_vbq);
videobuf_mmap_free(&pxp->s0_vbq);
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 01b633c73480..be99c8797dcc 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -707,6 +707,10 @@ static void uvc_video_complete(struct urb *urb)
if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
ret);
+ if (ret == -ENODEV) {
+ uvc_queue_cancel(queue, 1);
+ return;
+ }
}
}
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
index 2ac8c2421ad2..dc4f32bbd83d 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -319,7 +319,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
mem->size = PAGE_ALIGN(q->bufs[first]->bsize);
mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
- &mem->dma_handle, GFP_KERNEL);
+ &mem->dma_handle, GFP_DMA);
if (!mem->vaddr) {
dev_err(q->dev, "dma_alloc_coherent size %ld failed\n",
mem->size);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 281b61b3b5f3..72c10192d802 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -13,6 +13,10 @@ menuconfig MISC_DEVICES
if MISC_DEVICES
+config ANDROID_PMEM
+ bool "Android pmem allocator"
+ default y
+
config ATMEL_PWM
tristate "Atmel AT32/AT91 PWM support"
depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9
@@ -238,6 +242,14 @@ config MXS_PERSISTENT
depends on ARCH_MXS
default y
+config UID_STAT
+ bool "UID based statistics tracking exported to /proc/uid_stat"
+ default n
+
+config FSL_CACHE
+ tristate "Freescale Cache manipulate driver"
+ default n
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 03dd5ee05ce2..c435ec82d664 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -21,5 +21,8 @@ obj-$(CONFIG_HP_ILO) += hpilo.o
obj-$(CONFIG_ISL29003) += isl29003.o
obj-$(CONFIG_C2PORT) += c2port/
obj-$(CONFIG_MXS_PERSISTENT) += mxs-persistent.o
+obj-$(CONFIG_ANDROID_PMEM) += pmem.o
+obj-$(CONFIG_UID_STAT) += uid_stat.o
+obj-$(CONFIG_FSL_CACHE) += fsl_cache.o
obj-y += eeprom/
obj-y += cb710/
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index ab37a6d9d32a..bb22ffd76ef8 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -3,7 +3,7 @@
#
config MMC_UNSAFE_RESUME
- bool "Allow unsafe resume (DANGEROUS)"
+ bool "Assume MMC/SD cards are non-removable (DANGEROUS)"
help
If you say Y here, the MMC layer will assume that all cards
stayed in their respective slots during the suspend. The
@@ -14,3 +14,5 @@ config MMC_UNSAFE_RESUME
This option is usually just for embedded systems which use
a MMC/SD card for rootfs. Most people should say N here.
+ This option sets a default which can be overridden by the
+ module parameter "removable=0" or "removable=1".
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 50b208253440..91ba2f812d73 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -48,6 +48,22 @@ int use_spi_crc = 1;
module_param(use_spi_crc, bool, 0);
/*
+ * We normally treat cards as removed during suspend if they are not
+ * known to be on a non-removable bus, to avoid the risk of writing
+ * back data to a different card after resume. Allow this to be
+ * overridden if necessary.
+ */
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+int mmc_assume_removable;
+#else
+int mmc_assume_removable = 1;
+#endif
+module_param_named(removable, mmc_assume_removable, bool, 0644);
+MODULE_PARM_DESC(
+ removable,
+ "MMC/SD cards are removable and may be removed during suspend");
+
+/*
* Internal function. Schedule delayed work in the MMC work queue.
*/
static int mmc_schedule_delayed_work(struct delayed_work *work,
@@ -344,6 +360,101 @@ unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz)
EXPORT_SYMBOL(mmc_align_data_size);
/**
+ * mmc_host_enable - enable a host.
+ * @host: mmc host to enable
+ *
+ * Hosts that support power saving can use the 'enable' and 'disable'
+ * methods to exit and enter power saving states. For more information
+ * see comments for struct mmc_host_ops.
+ */
+int mmc_host_enable(struct mmc_host *host)
+{
+ if (!(host->caps & MMC_CAP_DISABLE))
+ return 0;
+
+ if (host->en_dis_recurs)
+ return 0;
+
+ if (host->nesting_cnt++)
+ return 0;
+
+ cancel_delayed_work_sync(&host->disable);
+
+ if (host->enabled)
+ return 0;
+
+ if (host->ops->enable) {
+ int err;
+
+ host->en_dis_recurs = 1;
+ err = host->ops->enable(host);
+ host->en_dis_recurs = 0;
+
+ if (err) {
+ pr_debug("%s: enable error %d\n",
+ mmc_hostname(host), err);
+ return err;
+ }
+ }
+ host->enabled = 1;
+ return 0;
+}
+EXPORT_SYMBOL(mmc_host_enable);
+
+static int mmc_host_do_disable(struct mmc_host *host, int lazy)
+{
+ if (host->ops->disable) {
+ int err;
+
+ host->en_dis_recurs = 1;
+ err = host->ops->disable(host, lazy);
+ host->en_dis_recurs = 0;
+
+ if (err < 0) {
+ pr_debug("%s: disable error %d\n",
+ mmc_hostname(host), err);
+ return err;
+ }
+ if (err > 0) {
+ unsigned long delay = msecs_to_jiffies(err);
+
+ mmc_schedule_delayed_work(&host->disable, delay);
+ }
+ }
+ host->enabled = 0;
+ return 0;
+}
+
+/**
+ * mmc_host_disable - disable a host.
+ * @host: mmc host to disable
+ *
+ * Hosts that support power saving can use the 'enable' and 'disable'
+ * methods to exit and enter power saving states. For more information
+ * see comments for struct mmc_host_ops.
+ */
+int mmc_host_disable(struct mmc_host *host)
+{
+ int err;
+
+ if (!(host->caps & MMC_CAP_DISABLE))
+ return 0;
+
+ if (host->en_dis_recurs)
+ return 0;
+
+ if (--host->nesting_cnt)
+ return 0;
+
+ if (!host->enabled)
+ return 0;
+
+ err = mmc_host_do_disable(host, 0);
+ return err;
+}
+EXPORT_SYMBOL(mmc_host_disable);
+
+/**
* __mmc_claim_host - exclusively claim a host
* @host: mmc host to claim
* @abort: whether or not the operation should be aborted
@@ -366,25 +477,111 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
stop = abort ? atomic_read(abort) : 0;
- if (stop || !host->claimed)
+ if (stop || !host->claimed || host->claimer == current)
break;
spin_unlock_irqrestore(&host->lock, flags);
schedule();
spin_lock_irqsave(&host->lock, flags);
}
set_current_state(TASK_RUNNING);
- if (!stop)
+ if (!stop) {
host->claimed = 1;
- else
+ host->claimer = current;
+ host->claim_cnt += 1;
+ } else
wake_up(&host->wq);
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
+ if (!stop)
+ mmc_host_enable(host);
return stop;
}
EXPORT_SYMBOL(__mmc_claim_host);
/**
+ * mmc_try_claim_host - try exclusively to claim a host
+ * @host: mmc host to claim
+ *
+ * Returns %1 if the host is claimed, %0 otherwise.
+ */
+int mmc_try_claim_host(struct mmc_host *host)
+{
+ int claimed_host = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (!host->claimed || host->claimer == current) {
+ host->claimed = 1;
+ host->claimer = current;
+ host->claim_cnt += 1;
+ claimed_host = 1;
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+ return claimed_host;
+}
+EXPORT_SYMBOL(mmc_try_claim_host);
+
+static void mmc_do_release_host(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (--host->claim_cnt) {
+ /* Release for nested claim */
+ spin_unlock_irqrestore(&host->lock, flags);
+ } else {
+ host->claimed = 0;
+ host->claimer = NULL;
+ spin_unlock_irqrestore(&host->lock, flags);
+ wake_up(&host->wq);
+ }
+}
+
+void mmc_host_deeper_disable(struct work_struct *work)
+{
+ struct mmc_host *host =
+ container_of(work, struct mmc_host, disable.work);
+
+ /* If the host is claimed then we do not want to disable it anymore */
+ if (!mmc_try_claim_host(host))
+ return;
+ mmc_host_do_disable(host, 1);
+ mmc_do_release_host(host);
+}
+
+/**
+ * mmc_host_lazy_disable - lazily disable a host.
+ * @host: mmc host to disable
+ *
+ * Hosts that support power saving can use the 'enable' and 'disable'
+ * methods to exit and enter power saving states. For more information
+ * see comments for struct mmc_host_ops.
+ */
+int mmc_host_lazy_disable(struct mmc_host *host)
+{
+ if (!(host->caps & MMC_CAP_DISABLE))
+ return 0;
+
+ if (host->en_dis_recurs)
+ return 0;
+
+ if (--host->nesting_cnt)
+ return 0;
+
+ if (!host->enabled)
+ return 0;
+
+ if (host->disable_delay) {
+ mmc_schedule_delayed_work(&host->disable,
+ msecs_to_jiffies(host->disable_delay));
+ return 0;
+ } else
+ return mmc_host_do_disable(host, 1);
+}
+EXPORT_SYMBOL(mmc_host_lazy_disable);
+
+/**
* mmc_release_host - release a host
* @host: mmc host to release
*
@@ -393,15 +590,11 @@ EXPORT_SYMBOL(__mmc_claim_host);
*/
void mmc_release_host(struct mmc_host *host)
{
- unsigned long flags;
-
WARN_ON(!host->claimed);
- spin_lock_irqsave(&host->lock, flags);
- host->claimed = 0;
- spin_unlock_irqrestore(&host->lock, flags);
+ mmc_host_lazy_disable(host);
- wake_up(&host->wq);
+ mmc_do_release_host(host);
}
EXPORT_SYMBOL(mmc_release_host);
@@ -687,7 +880,13 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing)
*/
static void mmc_power_up(struct mmc_host *host)
{
- int bit = fls(host->ocr_avail) - 1;
+ int bit;
+
+ /* If ocr is set, we use it */
+ if (host->ocr)
+ bit = ffs(host->ocr) - 1;
+ else
+ bit = fls(host->ocr_avail) - 1;
host->ios.vdd = bit;
if (mmc_host_is_spi(host)) {
@@ -858,6 +1057,17 @@ void mmc_rescan(struct work_struct *work)
container_of(work, struct mmc_host, detect.work);
u32 ocr;
int err;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (host->rescan_disable) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ return;
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
mmc_bus_get(host);
@@ -890,8 +1100,7 @@ void mmc_rescan(struct work_struct *work)
mmc_claim_host(host);
mmc_power_up(host);
- sdio_go_idle(host);
-
+ sdio_reset(host);
mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail);
@@ -949,9 +1158,14 @@ void mmc_stop_host(struct mmc_host *host)
spin_unlock_irqrestore(&host->lock, flags);
#endif
+ if (host->caps & MMC_CAP_DISABLE)
+ cancel_delayed_work(&host->disable);
cancel_delayed_work(&host->detect);
mmc_flush_scheduled_work();
+ /* clear pm flags now and let card drivers set them as needed */
+ host->pm_flags = 0;
+
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
if (host->bus_ops->remove)
@@ -960,6 +1174,8 @@ void mmc_stop_host(struct mmc_host *host)
mmc_claim_host(host);
mmc_detach_bus(host);
mmc_release_host(host);
+ mmc_bus_put(host);
+ return;
}
mmc_bus_put(host);
@@ -968,6 +1184,80 @@ void mmc_stop_host(struct mmc_host *host)
mmc_power_off(host);
}
+void mmc_power_save_host(struct mmc_host *host)
+{
+ mmc_bus_get(host);
+
+ if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
+ mmc_bus_put(host);
+ return;
+ }
+
+ if (host->bus_ops->power_save)
+ host->bus_ops->power_save(host);
+
+ mmc_bus_put(host);
+
+ mmc_power_off(host);
+}
+EXPORT_SYMBOL(mmc_power_save_host);
+
+void mmc_power_restore_host(struct mmc_host *host)
+{
+ mmc_bus_get(host);
+
+ if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
+ mmc_bus_put(host);
+ return;
+ }
+
+ mmc_power_up(host);
+ host->bus_ops->power_restore(host);
+
+ mmc_bus_put(host);
+}
+EXPORT_SYMBOL(mmc_power_restore_host);
+
+int mmc_card_awake(struct mmc_host *host)
+{
+ int err = -ENOSYS;
+
+ mmc_bus_get(host);
+
+ if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
+ err = host->bus_ops->awake(host);
+
+ mmc_bus_put(host);
+
+ return err;
+}
+EXPORT_SYMBOL(mmc_card_awake);
+
+int mmc_card_sleep(struct mmc_host *host)
+{
+ int err = -ENOSYS;
+
+ mmc_bus_get(host);
+
+ if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
+ err = host->bus_ops->sleep(host);
+
+ mmc_bus_put(host);
+
+ return err;
+}
+EXPORT_SYMBOL(mmc_card_sleep);
+
+int mmc_card_can_sleep(struct mmc_host *host)
+{
+ struct mmc_card *card = host->card;
+
+ if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3)
+ return 1;
+ return 0;
+}
+EXPORT_SYMBOL(mmc_card_can_sleep);
+
#ifdef CONFIG_PM
/**
@@ -977,27 +1267,37 @@ void mmc_stop_host(struct mmc_host *host)
*/
int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
{
+ int err = 0;
+
+ if (host->caps & MMC_CAP_DISABLE)
+ cancel_delayed_work(&host->disable);
cancel_delayed_work(&host->detect);
mmc_flush_scheduled_work();
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
if (host->bus_ops->suspend)
- host->bus_ops->suspend(host);
- if (!host->bus_ops->resume) {
+ err = host->bus_ops->suspend(host);
+ if (err == -ENOSYS || !host->bus_ops->resume) {
+ /*
+ * We simply "remove" the card in this case.
+ * It will be redetected on resume.
+ */
if (host->bus_ops->remove)
host->bus_ops->remove(host);
-
mmc_claim_host(host);
mmc_detach_bus(host);
mmc_release_host(host);
+ host->pm_flags = 0;
+ err = 0;
}
}
mmc_bus_put(host);
- mmc_power_off(host);
+ if (!err && !(host->pm_flags & MMC_PM_KEEP_POWER))
+ mmc_power_off(host);
- return 0;
+ return err;
}
EXPORT_SYMBOL(mmc_suspend_host);
@@ -1008,26 +1308,75 @@ EXPORT_SYMBOL(mmc_suspend_host);
*/
int mmc_resume_host(struct mmc_host *host)
{
+ int err = 0;
+
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
- mmc_power_up(host);
- mmc_select_voltage(host, host->ocr);
+ if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
+ mmc_power_up(host);
+ mmc_select_voltage(host, host->ocr);
+ }
BUG_ON(!host->bus_ops->resume);
- host->bus_ops->resume(host);
+ err = host->bus_ops->resume(host);
+ if (err) {
+ printk(KERN_WARNING "%s: error %d during resume "
+ "(card was removed?)\n",
+ mmc_hostname(host), err);
+ err = 0;
+ }
}
mmc_bus_put(host);
- /*
- * We add a slight delay here so that resume can progress
- * in parallel.
- */
- mmc_detect_change(host, 1);
-
- return 0;
+ return err;
}
-
EXPORT_SYMBOL(mmc_resume_host);
+/* Do the card removal on suspend if card is assumed removeable
+ * Do that in pm notifier while userspace isn't yet frozen, so we will be able
+ to sync the card.
+*/
+int mmc_pm_notify(struct notifier_block *notify_block,
+ unsigned long mode, void *unused)
+{
+ struct mmc_host *host = container_of(
+ notify_block, struct mmc_host, pm_notify);
+ unsigned long flags;
+
+
+ switch (mode) {
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->rescan_disable = 1;
+ spin_unlock_irqrestore(&host->lock, flags);
+ cancel_delayed_work_sync(&host->detect);
+
+ if (!host->bus_ops || host->bus_ops->suspend)
+ break;
+
+ mmc_claim_host(host);
+
+ if (host->bus_ops->remove)
+ host->bus_ops->remove(host);
+
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+ host->pm_flags = 0;
+ break;
+
+ case PM_POST_SUSPEND:
+ case PM_POST_HIBERNATION:
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->rescan_disable = 0;
+ spin_unlock_irqrestore(&host->lock, flags);
+ mmc_detect_change(host, 0);
+
+ }
+
+ return 0;
+}
#endif
static int __init mmc_init(void)
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index c819effa1032..a811c52a1659 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -16,10 +16,14 @@
#define MMC_CMD_RETRIES 3
struct mmc_bus_ops {
+ int (*awake)(struct mmc_host *);
+ int (*sleep)(struct mmc_host *);
void (*remove)(struct mmc_host *);
void (*detect)(struct mmc_host *);
- void (*suspend)(struct mmc_host *);
- void (*resume)(struct mmc_host *);
+ int (*suspend)(struct mmc_host *);
+ int (*resume)(struct mmc_host *);
+ void (*power_save)(struct mmc_host *);
+ void (*power_restore)(struct mmc_host *);
};
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -50,7 +54,9 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
int mmc_attach_sd(struct mmc_host *host, u32 ocr);
int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
+/* Module parameters */
extern int use_spi_crc;
+extern int mmc_assume_removable;
/* Debugfs information for hosts and cards */
void mmc_add_host_debugfs(struct mmc_host *host);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 5e945e64ead7..0efe631e50ca 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -16,6 +16,8 @@
#include <linux/idr.h>
#include <linux/pagemap.h>
#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
#include <linux/mmc/host.h>
@@ -83,6 +85,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
+ INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);
+ host->pm_notify.notifier_call = mmc_pm_notify;
/*
* By default, hosts do not support SGIO or large requests.
@@ -131,6 +135,7 @@ int mmc_add_host(struct mmc_host *host)
#endif
mmc_start_host(host);
+ register_pm_notifier(&host->pm_notify);
return 0;
}
@@ -147,6 +152,7 @@ EXPORT_SYMBOL(mmc_add_host);
*/
void mmc_remove_host(struct mmc_host *host)
{
+ unregister_pm_notifier(&host->pm_notify);
mmc_stop_host(host);
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index c2dc3d2d9f9a..8c87e1109a34 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -14,5 +14,7 @@
int mmc_register_host_class(void);
void mmc_unregister_host_class(void);
+void mmc_host_deeper_disable(struct work_struct *work);
+
#endif
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index e207dcf9e754..2338c761c74f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -160,7 +160,6 @@ static int mmc_read_ext_csd(struct mmc_card *card)
{
int err;
u8 *ext_csd;
- unsigned int ext_csd_struct;
BUG_ON(!card);
@@ -207,16 +206,16 @@ static int mmc_read_ext_csd(struct mmc_card *card)
goto out;
}
- ext_csd_struct = ext_csd[EXT_CSD_REV];
- if (ext_csd_struct > 5) {
+ card->ext_csd.rev = ext_csd[EXT_CSD_REV];
+ if (card->ext_csd.rev > 3) {
printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
"version %d\n", mmc_hostname(card->host),
- ext_csd_struct);
+ card->ext_csd.rev);
err = -EINVAL;
goto out;
}
- if (ext_csd_struct >= 2) {
+ if (card->ext_csd.rev >= 2) {
card->ext_csd.sectors =
ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
@@ -226,7 +225,17 @@ static int mmc_read_ext_csd(struct mmc_card *card)
mmc_card_set_blockaddr(card);
}
+ card->ext_csd.boot_info = ext_csd[EXT_CSD_BOOT_INFO];
+ card->ext_csd.boot_size_mult = ext_csd[EXT_CSD_BOOT_SIZE_MULT];
+ card->ext_csd.boot_config = ext_csd[EXT_CSD_BOOT_CONFIG];
+ card->ext_csd.boot_bus_width = ext_csd[EXT_CSD_BOOT_BUS_WIDTH];
+ card->ext_csd.card_type = ext_csd[EXT_CSD_CARD_TYPE];
+
switch (ext_csd[EXT_CSD_CARD_TYPE]) {
+ case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52
+ | EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 52000000;
+ break;
case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
card->ext_csd.hs_max_dtr = 52000000;
break;
@@ -238,15 +247,301 @@ static int mmc_read_ext_csd(struct mmc_card *card)
printk(KERN_WARNING "%s: card is mmc v4 but doesn't "
"support any high-speed modes.\n",
mmc_hostname(card->host));
+ printk(KERN_WARNING "%s: card type is 0x%x\n",
+ mmc_hostname(card->host), ext_csd[EXT_CSD_CARD_TYPE]);
goto out;
}
+ if (card->ext_csd.rev >= 3) {
+ u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
+
+ /* Sleep / awake timeout in 100ns units */
+ if (sa_shift > 0 && sa_shift <= 0x17)
+ card->ext_csd.sa_timeout =
+ 1 << ext_csd[EXT_CSD_S_A_TIMEOUT];
+ }
+
out:
kfree(ext_csd);
return err;
}
+/* configure the boot partitions */
+static ssize_t
+setup_boot_partitions(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err, busy = 0;
+ u32 part, new_part;
+ u8 *ext_csd, boot_config;
+ struct mmc_command cmd;
+ struct mmc_card *card = container_of(dev, struct mmc_card, dev);
+
+ BUG_ON(!card);
+
+ sscanf(buf, "%d\n", &part);
+
+ if (card->csd.mmca_vsn < CSD_SPEC_VER_4) {
+ printk(KERN_ERR "%s: invalid mmc version"
+ " mmc version is below version 4!)\n",
+ mmc_hostname(card->host));
+ return -EINVAL;
+ }
+
+ /* it's a normal SD/MMC but user request to configure boot partition */
+ if (card->ext_csd.boot_size_mult <= 0) {
+ printk(KERN_ERR "%s: this is a normal SD/MMC card"
+ " but you request to access boot partition!\n",
+ mmc_hostname(card->host));
+ return -EINVAL;
+ }
+
+ ext_csd = kmalloc(512, GFP_KERNEL);
+ if (!ext_csd) {
+ printk(KERN_ERR "%s: could not allocate a buffer to "
+ "receive the ext_csd.\n", mmc_hostname(card->host));
+ return -ENOMEM;
+ }
+
+ mmc_claim_host(card->host);
+ err = mmc_send_ext_csd(card, ext_csd);
+ if (err) {
+ printk(KERN_ERR "%s: unable to read EXT_CSD.\n",
+ mmc_hostname(card->host));
+ goto err_rtn;
+ }
+
+ /* enable the boot partition in boot mode */
+ /* boot enable be -
+ * 0x00 - disable boot enable.
+ * 0x08 - boot partition 1 is enabled for boot.
+ * 0x10 - boot partition 2 is enabled for boot.
+ * 0x38 - User area is enabled for boot.
+ */
+ switch (part & EXT_CSD_BOOT_PARTITION_ENABLE_MASK) {
+ case 0:
+ boot_config = (ext_csd[EXT_CSD_BOOT_CONFIG]
+ & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK
+ & ~EXT_CSD_BOOT_ACK_ENABLE);
+ break;
+ case EXT_CSD_BOOT_PARTITION_PART1:
+ boot_config = ((ext_csd[EXT_CSD_BOOT_CONFIG]
+ & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK)
+ | EXT_CSD_BOOT_PARTITION_PART1
+ | EXT_CSD_BOOT_ACK_ENABLE);
+ break;
+ case EXT_CSD_BOOT_PARTITION_PART2:
+ boot_config = ((ext_csd[EXT_CSD_BOOT_CONFIG]
+ & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK)
+ | EXT_CSD_BOOT_PARTITION_PART2
+ | EXT_CSD_BOOT_ACK_ENABLE);
+ break;
+ case EXT_CSD_BOOT_PARTITION_ENABLE_MASK:
+ boot_config = ((ext_csd[EXT_CSD_BOOT_CONFIG]
+ | EXT_CSD_BOOT_PARTITION_ENABLE_MASK)
+ & ~EXT_CSD_BOOT_ACK_ENABLE);
+ break;
+ default:
+ printk(KERN_ERR "%s: wrong boot config parameter"
+ " 00 (disable boot), 08 (enable boot1),"
+ "16 (enable boot2), 56 (User area)\n",
+ mmc_hostname(card->host));
+ err = -EINVAL;
+ goto err_rtn;
+ }
+
+ /* switch the partitions that used to be accessed in OS layer */
+ /* partition must be -
+ * 0 - user area
+ * 1 - boot partition 1
+ * 2 - boot partition 2
+ */
+ if ((part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK) > 2) {
+ printk(KERN_ERR "%s: wrong partition id"
+ " 0 (user area), 1 (boot1), 2 (boot2)\n",
+ mmc_hostname(card->host));
+ err = -EINVAL;
+ goto err_rtn;
+ }
+
+ /* Send SWITCH command to change partition for access */
+ boot_config &= ~EXT_CSD_BOOT_PARTITION_ACCESS_MASK;
+ boot_config |= (part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK);
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BOOT_CONFIG, boot_config);
+ if (err) {
+ printk(KERN_ERR "%s: fail to send SWITCH command"
+ " to card to swich partition for access!\n",
+ mmc_hostname(card->host));
+ goto err_rtn;
+ }
+
+ /* waiting for the card to finish the busy state */
+ do {
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SEND_STATUS;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if (err || busy > 100) {
+ printk(KERN_ERR "%s: failed to wait for"
+ "the busy state to end.\n",
+ mmc_hostname(card->host));
+ break;
+ }
+
+ if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) {
+ printk(KERN_INFO "%s: card is in busy state"
+ "pls wait for busy state to end.\n",
+ mmc_hostname(card->host));
+ }
+ busy++;
+ } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
+
+ /* Now check whether it works */
+ err = mmc_send_ext_csd(card, ext_csd);
+ if (err) {
+ printk(KERN_ERR "%s: %d unable to re-read EXT_CSD.\n",
+ mmc_hostname(card->host), err);
+ goto err_rtn;
+ }
+
+ new_part = ext_csd[EXT_CSD_BOOT_CONFIG] &
+ EXT_CSD_BOOT_PARTITION_ACCESS_MASK;
+ if ((part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK) != new_part) {
+ printk(KERN_ERR "%s: after SWITCH, current part id %d is not"
+ " same as requested partition %d!\n",
+ mmc_hostname(card->host), new_part, part);
+ goto err_rtn;
+ }
+ card->ext_csd.boot_config = ext_csd[EXT_CSD_BOOT_CONFIG];
+
+err_rtn:
+ mmc_release_host(card->host);
+ kfree(ext_csd);
+ if (err)
+ return err;
+ else
+ return count;
+}
+
+/* configure the boot bus */
+static ssize_t
+setup_boot_bus(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err, busy = 0;
+ u32 boot_bus, new_bus;
+ u8 *ext_csd;
+ struct mmc_command cmd;
+ struct mmc_card *card = container_of(dev, struct mmc_card, dev);
+
+ BUG_ON(!card);
+
+ sscanf(buf, "%d\n", &boot_bus);
+
+ if (card->csd.mmca_vsn < CSD_SPEC_VER_4) {
+ printk(KERN_ERR "%s: invalid mmc version"
+ " mmc version is below version 4!)\n",
+ mmc_hostname(card->host));
+ return -EINVAL;
+ }
+
+ /* it's a normal SD/MMC but user request to configure boot bus */
+ if (card->ext_csd.boot_size_mult <= 0) {
+ printk(KERN_ERR "%s: this is a normal SD/MMC card"
+ " but you request to configure boot bus !\n",
+ mmc_hostname(card->host));
+ return -EINVAL;
+ }
+
+ ext_csd = kmalloc(512, GFP_KERNEL);
+ if (!ext_csd) {
+ printk(KERN_ERR "%s: could not allocate a buffer to "
+ "receive the ext_csd.\n", mmc_hostname(card->host));
+ return -ENOMEM;
+ }
+
+ mmc_claim_host(card->host);
+ err = mmc_send_ext_csd(card, ext_csd);
+ if (err) {
+ printk(KERN_ERR "%s: unable to read EXT_CSD.\n",
+ mmc_hostname(card->host));
+ goto err_rtn;
+ }
+
+ /* Configure the boot bus width when boot partition is enabled */
+ if (((boot_bus & EXT_CSD_BOOT_BUS_WIDTH_MODE_MASK) >> 3) > 2
+ || (boot_bus & EXT_CSD_BOOT_BUS_WIDTH_WIDTH_MASK) > 2
+ || (boot_bus & ~EXT_CSD_BOOT_BUS_WIDTH_MASK) > 0) {
+ printk(KERN_ERR "%s: Invalid inputs!\n",
+ mmc_hostname(card->host));
+ err = -EINVAL;
+ goto err_rtn;
+ }
+
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BOOT_BUS_WIDTH, boot_bus);
+ if (err) {
+ printk(KERN_ERR "%s: fail to send SWITCH command to "
+ "card to swich partition for access!\n",
+ mmc_hostname(card->host));
+ goto err_rtn;
+ }
+
+ /* waiting for the card to finish the busy state */
+ do {
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SEND_STATUS;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if (err || busy > 100) {
+ printk(KERN_ERR "%s: failed to wait for"
+ "the busy state to end.\n",
+ mmc_hostname(card->host));
+ break;
+ }
+
+ if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) {
+ printk(KERN_INFO "%s: card is in busy state"
+ "pls wait for busy state to end.\n",
+ mmc_hostname(card->host));
+ }
+ busy++;
+ } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
+
+ /* Now check whether it works */
+ err = mmc_send_ext_csd(card, ext_csd);
+ if (err) {
+ printk(KERN_ERR "%s: %d unable to re-read EXT_CSD.\n",
+ mmc_hostname(card->host), err);
+ goto err_rtn;
+ }
+
+ new_bus = ext_csd[EXT_CSD_BOOT_BUS_WIDTH];
+ if (boot_bus != new_bus) {
+ printk(KERN_ERR "%s: after SWITCH, current boot bus mode %d"
+ " is not same as requested bus mode %d!\n",
+ mmc_hostname(card->host), new_bus, boot_bus);
+ goto err_rtn;
+ }
+ card->ext_csd.boot_bus_width = ext_csd[EXT_CSD_BOOT_BUS_WIDTH];
+
+err_rtn:
+ mmc_release_host(card->host);
+ kfree(ext_csd);
+ if (err)
+ return err;
+ else
+ return count;
+}
+
MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
card->raw_cid[2], card->raw_cid[3]);
MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
@@ -258,6 +553,12 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
+MMC_DEV_ATTR(boot_info, "boot_info:0x%02x; boot_size:%04dKB;"
+ " boot_partition:0x%02x; boot_bus:0x%02x\n",
+ card->ext_csd.boot_info, card->ext_csd.boot_size_mult * 128,
+ card->ext_csd.boot_config, card->ext_csd.boot_bus_width);
+DEVICE_ATTR(boot_config, S_IWUGO, NULL, setup_boot_partitions);
+DEVICE_ATTR(boot_bus_config, S_IWUGO, NULL, setup_boot_bus);
static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr,
@@ -269,6 +570,9 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_name.attr,
&dev_attr_oemid.attr,
&dev_attr_serial.attr,
+ &dev_attr_boot_info.attr,
+ &dev_attr_boot_config.attr,
+ &dev_attr_boot_bus_config.attr,
NULL,
};
@@ -434,10 +738,21 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
* Activate wide bus (if supported).
*/
if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
- (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
+ (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA
+ | MMC_CAP_DATA_DDR))) {
unsigned ext_csd_bit, bus_width;
- if (host->caps & MMC_CAP_8_BIT_DATA) {
+ if ((host->caps & MMC_CAP_8_BIT_DATA) &&
+ (host->caps & MMC_CAP_DATA_DDR) &&
+ (card->ext_csd.card_type & MMC_DDR_MODE_MASK)) {
+ ext_csd_bit = EXT_CSD_BUS_WIDTH_8_DDR;
+ bus_width = MMC_BUS_WIDTH_8 | MMC_BUS_WIDTH_DDR;
+ } else if ((host->caps & MMC_CAP_4_BIT_DATA) &&
+ (host->caps & MMC_CAP_DATA_DDR) &&
+ (card->ext_csd.card_type & MMC_DDR_MODE_MASK)) {
+ ext_csd_bit = EXT_CSD_BUS_WIDTH_4_DDR;
+ bus_width = MMC_BUS_WIDTH_4 | MMC_BUS_WIDTH_DDR;
+ } else if (host->caps & MMC_CAP_8_BIT_DATA) {
ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
bus_width = MMC_BUS_WIDTH_8;
} else {
@@ -507,12 +822,10 @@ static void mmc_detect(struct mmc_host *host)
}
}
-#ifdef CONFIG_MMC_UNSAFE_RESUME
-
/*
* Suspend callback from host.
*/
-static void mmc_suspend(struct mmc_host *host)
+static int mmc_suspend(struct mmc_host *host)
{
BUG_ON(!host);
BUG_ON(!host->card);
@@ -522,6 +835,8 @@ static void mmc_suspend(struct mmc_host *host)
mmc_deselect_cards(host);
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_release_host(host);
+
+ return 0;
}
/*
@@ -530,7 +845,7 @@ static void mmc_suspend(struct mmc_host *host)
* This function tries to determine if the same card is still present
* and, if so, restore all state to it.
*/
-static void mmc_resume(struct mmc_host *host)
+static int mmc_resume(struct mmc_host *host)
{
int err;
@@ -541,30 +856,78 @@ static void mmc_resume(struct mmc_host *host)
err = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
- if (err) {
- mmc_remove(host);
+ return err;
+}
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_release_host(host);
+static void mmc_power_restore(struct mmc_host *host)
+{
+ host->card->state &= ~MMC_STATE_HIGHSPEED;
+ mmc_claim_host(host);
+ mmc_init_card(host, host->ocr, host->card);
+ mmc_release_host(host);
+}
+
+static int mmc_sleep(struct mmc_host *host)
+{
+ struct mmc_card *card = host->card;
+ int err = -ENOSYS;
+
+ if (card && card->ext_csd.rev >= 3) {
+ err = mmc_card_sleepawake(host, 1);
+ if (err < 0)
+ pr_debug("%s: Error %d while putting card into sleep",
+ mmc_hostname(host), err);
}
+ return err;
}
-#else
-
-#define mmc_suspend NULL
-#define mmc_resume NULL
+static int mmc_awake(struct mmc_host *host)
+{
+ struct mmc_card *card = host->card;
+ int err = -ENOSYS;
+
+ if (card && card->ext_csd.rev >= 3) {
+ err = mmc_card_sleepawake(host, 0);
+ if (err < 0)
+ pr_debug("%s: Error %d while awaking sleeping card",
+ mmc_hostname(host), err);
+ }
-#endif
+ return err;
+}
static const struct mmc_bus_ops mmc_ops = {
+ .awake = mmc_awake,
+ .sleep = mmc_sleep,
+ .remove = mmc_remove,
+ .detect = mmc_detect,
+ .suspend = NULL,
+ .resume = NULL,
+ .power_restore = mmc_power_restore,
+};
+
+static const struct mmc_bus_ops mmc_ops_unsafe = {
+ .awake = mmc_awake,
+ .sleep = mmc_sleep,
.remove = mmc_remove,
.detect = mmc_detect,
.suspend = mmc_suspend,
.resume = mmc_resume,
+ .power_restore = mmc_power_restore,
};
+static void mmc_attach_bus_ops(struct mmc_host *host)
+{
+ const struct mmc_bus_ops *bus_ops;
+
+ if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable)
+ bus_ops = &mmc_ops_unsafe;
+ else
+ bus_ops = &mmc_ops;
+ mmc_attach_bus(host, bus_ops);
+}
+
/*
* Starting point for MMC card init.
*/
@@ -575,7 +938,7 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
BUG_ON(!host);
WARN_ON(!host->claimed);
- mmc_attach_bus(host, &mmc_ops);
+ mmc_attach_bus_ops(host);
/*
* We need to get OCR a different way for SPI.
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 34ce2703d29a..355c6042cf65 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -57,6 +57,42 @@ int mmc_deselect_cards(struct mmc_host *host)
return _mmc_select_card(host, NULL);
}
+int mmc_card_sleepawake(struct mmc_host *host, int sleep)
+{
+ struct mmc_command cmd;
+ struct mmc_card *card = host->card;
+ int err;
+
+ if (sleep)
+ mmc_deselect_cards(host);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SLEEP_AWAKE;
+ cmd.arg = card->rca << 16;
+ if (sleep)
+ cmd.arg |= 1 << 15;
+
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err)
+ return err;
+
+ /*
+ * If the host does not wait while the card signals busy, then we will
+ * will have to wait the sleep/awake timeout. Note, we cannot use the
+ * SEND_STATUS command to poll the status because that command (and most
+ * others) is invalid while the card sleeps.
+ */
+ if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+ mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
+
+ if (!sleep)
+ err = mmc_select_card(card);
+
+ return err;
+}
+
int mmc_go_idle(struct mmc_host *host)
{
int err;
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 17854bf7cf0d..653eb8e84178 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -25,6 +25,7 @@ int mmc_send_status(struct mmc_card *card, u32 *status);
int mmc_send_cid(struct mmc_host *host, u32 *cid);
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
+int mmc_card_sleepawake(struct mmc_host *host, int sleep);
#endif
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index cd81c395e164..4a73e34f9200 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -561,12 +561,10 @@ static void mmc_sd_detect(struct mmc_host *host)
}
}
-#ifdef CONFIG_MMC_UNSAFE_RESUME
-
/*
* Suspend callback from host.
*/
-static void mmc_sd_suspend(struct mmc_host *host)
+static int mmc_sd_suspend(struct mmc_host *host)
{
BUG_ON(!host);
BUG_ON(!host->card);
@@ -576,6 +574,8 @@ static void mmc_sd_suspend(struct mmc_host *host)
mmc_deselect_cards(host);
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_release_host(host);
+
+ return 0;
}
/*
@@ -584,7 +584,7 @@ static void mmc_sd_suspend(struct mmc_host *host)
* This function tries to determine if the same card is still present
* and, if so, restore all state to it.
*/
-static void mmc_sd_resume(struct mmc_host *host)
+static int mmc_sd_resume(struct mmc_host *host)
{
int err;
@@ -595,30 +595,44 @@ static void mmc_sd_resume(struct mmc_host *host)
err = mmc_sd_init_card(host, host->ocr, host->card);
mmc_release_host(host);
- if (err) {
- mmc_sd_remove(host);
-
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_release_host(host);
- }
-
+ return err;
}
-#else
-
-#define mmc_sd_suspend NULL
-#define mmc_sd_resume NULL
-
-#endif
+static void mmc_sd_power_restore(struct mmc_host *host)
+{
+ host->card->state &= ~MMC_STATE_HIGHSPEED;
+ mmc_claim_host(host);
+ mmc_sd_init_card(host, host->ocr, host->card);
+ mmc_release_host(host);
+}
static const struct mmc_bus_ops mmc_sd_ops = {
.remove = mmc_sd_remove,
.detect = mmc_sd_detect,
+ .suspend = NULL,
+ .resume = NULL,
+ .power_restore = mmc_sd_power_restore,
+};
+
+static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
+ .remove = mmc_sd_remove,
+ .detect = mmc_sd_detect,
.suspend = mmc_sd_suspend,
.resume = mmc_sd_resume,
+ .power_restore = mmc_sd_power_restore,
};
+static void mmc_sd_attach_bus_ops(struct mmc_host *host)
+{
+ const struct mmc_bus_ops *bus_ops;
+
+ if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable)
+ bus_ops = &mmc_sd_ops_unsafe;
+ else
+ bus_ops = &mmc_sd_ops;
+ mmc_attach_bus(host, bus_ops);
+}
+
/*
* Starting point for SD card init.
*/
@@ -629,7 +643,7 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
BUG_ON(!host);
WARN_ON(!host->claimed);
- mmc_attach_bus(host, &mmc_sd_ops);
+ mmc_sd_attach_bus_ops(host);
/*
* We need to get OCR a different way for SPI.
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index fb99ccff9080..7f3093dd2b49 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -195,6 +195,135 @@ static int sdio_enable_hs(struct mmc_card *card)
}
/*
+ * Handle the detection and initialisation of a card.
+ *
+ * In the case of a resume, "oldcard" will contain the card
+ * we're trying to reinitialise.
+ */
+static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
+ struct mmc_card *oldcard)
+{
+ struct mmc_card *card;
+ int err;
+
+ BUG_ON(!host);
+ WARN_ON(!host->claimed);
+
+ /*
+ * Inform the card of the voltage
+ */
+ err = mmc_send_io_op_cond(host, host->ocr, &ocr);
+ if (err)
+ goto err;
+
+ /*
+ * For SPI, enable CRC as appropriate.
+ */
+ if (mmc_host_is_spi(host)) {
+ err = mmc_spi_set_crc(host, use_spi_crc);
+ if (err)
+ goto err;
+ }
+
+ /*
+ * Allocate card structure.
+ */
+ card = mmc_alloc_card(host, NULL);
+ if (IS_ERR(card)) {
+ err = PTR_ERR(card);
+ goto err;
+ }
+
+ card->type = MMC_TYPE_SDIO;
+
+ /*
+ * For native busses: set card RCA and quit open drain mode.
+ */
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_send_relative_addr(host, &card->rca);
+ if (err)
+ goto remove;
+
+ mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+ }
+
+ /*
+ * Select card, as all following commands rely on that.
+ */
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_select_card(card);
+ if (err)
+ goto remove;
+ }
+
+ /*
+ * Read the common registers.
+ */
+ err = sdio_read_cccr(card);
+ if (err)
+ goto remove;
+
+ /*
+ * Read the common CIS tuples.
+ */
+ err = sdio_read_common_cis(card);
+ if (err)
+ goto remove;
+
+ if (oldcard) {
+ int same = (card->cis.vendor == oldcard->cis.vendor &&
+ card->cis.device == oldcard->cis.device);
+ mmc_remove_card(card);
+ if (!same) {
+ err = -ENOENT;
+ goto err;
+ }
+ card = oldcard;
+ return 0;
+ }
+
+ /*
+ * Switch to high-speed (if supported).
+ */
+ err = sdio_enable_hs(card);
+ if (err)
+ goto remove;
+
+ /*
+ * Change to the card's maximum speed.
+ */
+ if (mmc_card_highspeed(card)) {
+ /*
+ * The SDIO specification doesn't mention how
+ * the CIS transfer speed register relates to
+ * high-speed, but it seems that 50 MHz is
+ * mandatory.
+ */
+ mmc_set_clock(host, 50000000);
+ } else {
+ mmc_set_clock(host, card->cis.max_dtr);
+ }
+
+ /*
+ * Switch to wider bus (if supported).
+ */
+ err = sdio_enable_wide(card);
+ if (err)
+ goto remove;
+
+ if (!oldcard)
+ host->card = card;
+ return 0;
+
+remove:
+ if (!oldcard)
+ mmc_remove_card(card);
+
+err:
+ return err;
+}
+
+/*
* Host is being removed. Free up the current card.
*/
static void mmc_sdio_remove(struct mmc_host *host)
@@ -243,10 +372,77 @@ static void mmc_sdio_detect(struct mmc_host *host)
}
}
+/*
+ * SDIO suspend. We need to suspend all functions separately.
+ * Therefore all registered functions must have drivers with suspend
+ * and resume methods. Failing that we simply remove the whole card.
+ */
+static int mmc_sdio_suspend(struct mmc_host *host)
+{
+ int i, err = 0;
+
+ for (i = 0; i < host->card->sdio_funcs; i++) {
+ struct sdio_func *func = host->card->sdio_func[i];
+ if (func && sdio_func_present(func) && func->dev.driver) {
+ const struct dev_pm_ops *pmops = func->dev.driver->pm;
+ if (!pmops || !pmops->suspend || !pmops->resume) {
+ /* force removal of entire card in that case */
+ err = -ENOSYS;
+ } else
+ err = pmops->suspend(&func->dev);
+ if (err)
+ break;
+ }
+ }
+ while (err && --i >= 0) {
+ struct sdio_func *func = host->card->sdio_func[i];
+ if (func && sdio_func_present(func) && func->dev.driver) {
+ const struct dev_pm_ops *pmops = func->dev.driver->pm;
+ pmops->resume(&func->dev);
+ }
+ }
+
+ return err;
+}
+
+static int mmc_sdio_resume(struct mmc_host *host)
+{
+ int i, err;
+
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ /* Basic card reinitialization. */
+ mmc_claim_host(host);
+ err = mmc_sdio_init_card(host, host->ocr, host->card);
+ mmc_release_host(host);
+
+ /*
+ * If the card looked to be the same as before suspending, then
+ * we proceed to resume all card functions. If one of them returns
+ * an error then we simply return that error to the core and the
+ * card will be redetected as new. It is the responsibility of
+ * the function driver to perform further tests with the extra
+ * knowledge it has of the card to confirm the card is indeed the
+ * same as before suspending (same MAC address for network cards,
+ * etc.) and return an error otherwise.
+ */
+ for (i = 0; !err && i < host->card->sdio_funcs; i++) {
+ struct sdio_func *func = host->card->sdio_func[i];
+ if (func && sdio_func_present(func) && func->dev.driver) {
+ const struct dev_pm_ops *pmops = func->dev.driver->pm;
+ err = pmops->resume(&func->dev);
+ }
+ }
+
+ return err;
+}
static const struct mmc_bus_ops mmc_sdio_ops = {
.remove = mmc_sdio_remove,
.detect = mmc_sdio_detect,
+ .suspend = mmc_sdio_suspend,
+ .resume = mmc_sdio_resume,
};
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
index f61fc2d4cd0a..ff69a2feecd5 100644
--- a/drivers/mmc/core/sdio_io.c
+++ b/drivers/mmc/core/sdio_io.c
@@ -635,3 +635,52 @@ void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
*err_ret = ret;
}
EXPORT_SYMBOL_GPL(sdio_f0_writeb);
+
+/**
+ * sdio_get_host_pm_caps - get host power management capabilities
+ * @func: SDIO function attached to host
+ *
+ * Returns a capability bitmask corresponding to power management
+ * features supported by the host controller that the card function
+ * might rely upon during a system suspend. The host doesn't need
+ * to be claimed, nor the function active, for this information to be
+ * obtained.
+ */
+mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func)
+{
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ return func->card->host->pm_caps;
+}
+EXPORT_SYMBOL_GPL(sdio_get_host_pm_caps);
+
+/**
+ * sdio_set_host_pm_flags - set wanted host power management capabilities
+ * @func: SDIO function attached to host
+ *
+ * Set a capability bitmask corresponding to wanted host controller
+ * power management features for the upcoming suspend state.
+ * This must be called, if needed, each time the suspend method of
+ * the function driver is called, and must contain only bits that
+ * were returned by sdio_get_host_pm_caps().
+ * The host doesn't need to be claimed, nor the function active,
+ * for this information to be set.
+ */
+int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags)
+{
+ struct mmc_host *host;
+
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ host = func->card->host;
+
+ if (flags & ~host->pm_caps)
+ return -EINVAL;
+
+ /* function suspend methods are serialized, hence no lock needed */
+ host->pm_flags |= flags;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sdio_set_host_pm_flags);
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index 208beeb23ed6..b6304fb8bf90 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -67,6 +67,61 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
return err;
}
+static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
+ unsigned addr, u8 in, u8 *out)
+{
+ struct mmc_command cmd;
+ int err;
+
+ BUG_ON(!host);
+ BUG_ON(fn > 7);
+
+ /* sanity check */
+ if (addr & ~0x1FFFF)
+ return -EINVAL;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_IO_RW_DIRECT;
+ cmd.arg = write ? 0x80000000 : 0x00000000;
+ cmd.arg |= fn << 28;
+ cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
+ cmd.arg |= addr << 9;
+ cmd.arg |= in;
+ cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err)
+ return err;
+
+ if (mmc_host_is_spi(host)) {
+ /* host driver already reported errors */
+ } else {
+ if (cmd.resp[0] & R5_ERROR)
+ return -EIO;
+ if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+ return -EINVAL;
+ if (cmd.resp[0] & R5_OUT_OF_RANGE)
+ return -ERANGE;
+ }
+
+ if (out) {
+ if (mmc_host_is_spi(host))
+ *out = (cmd.resp[0] >> 8) & 0xFF;
+ else
+ *out = cmd.resp[0] & 0xFF;
+ }
+
+ return 0;
+}
+
+int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
+ unsigned addr, u8 in, u8 *out)
+{
+ BUG_ON(!card);
+ return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out);
+}
+
int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
{
@@ -134,62 +189,7 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
return 0;
}
-static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
- unsigned addr, u8 in, u8 *out)
-{
- struct mmc_command cmd;
- int err;
-
- BUG_ON(!host);
- BUG_ON(fn > 7);
-
- /* sanity check */
- if (addr & ~0x1FFFF)
- return -EINVAL;
-
- memset(&cmd, 0, sizeof(struct mmc_command));
-
- cmd.opcode = SD_IO_RW_DIRECT;
- cmd.arg = write ? 0x80000000 : 0x00000000;
- cmd.arg |= fn << 28;
- cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
- cmd.arg |= addr << 9;
- cmd.arg |= in;
- cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err)
- return err;
-
- if (mmc_host_is_spi(host)) {
- /* host driver already reported errors */
- } else {
- if (cmd.resp[0] & R5_ERROR)
- return -EIO;
- if (cmd.resp[0] & R5_FUNCTION_NUMBER)
- return -EINVAL;
- if (cmd.resp[0] & R5_OUT_OF_RANGE)
- return -ERANGE;
- }
-
- if (out) {
- if (mmc_host_is_spi(host))
- *out = (cmd.resp[0] >> 8) & 0xFF;
- else
- *out = cmd.resp[0] & 0xFF;
- }
-
- return 0;
-}
-
-int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
- unsigned addr, u8 in, u8 *out)
-{
- BUG_ON(!card);
- return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out);
-}
-
-int sdio_go_idle(struct mmc_host *host)
+int sdio_reset(struct mmc_host *host)
{
int ret;
u8 abort;
diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h
index 9b546c71eb5e..85c7ecf809f4 100644
--- a/drivers/mmc/core/sdio_ops.h
+++ b/drivers/mmc/core/sdio_ops.h
@@ -18,6 +18,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
int sdio_go_idle(struct mmc_host *host);
+int sdio_reset(struct mmc_host *host);
#endif
diff --git a/drivers/mmc/host/mx_sdhci.c b/drivers/mmc/host/mx_sdhci.c
index 5a68a8e02fe2..732135308eb6 100644
--- a/drivers/mmc/host/mx_sdhci.c
+++ b/drivers/mmc/host/mx_sdhci.c
@@ -142,32 +142,32 @@ EXPORT_SYMBOL(mxc_mmc_force_detect);
static void sdhci_dumpregs(struct sdhci_host *host)
{
- printk(KERN_DEBUG DRIVER_NAME
+ printk(KERN_INFO DRIVER_NAME
": ============== REGISTER DUMP ==============\n");
- printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n",
+ printk(KERN_INFO DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n",
readl(host->ioaddr + SDHCI_DMA_ADDRESS),
readl(host->ioaddr + SDHCI_HOST_VERSION));
- printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n",
+ printk(KERN_INFO DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n",
(readl(host->ioaddr + SDHCI_BLOCK_SIZE) & 0xFFFF),
(readl(host->ioaddr + SDHCI_BLOCK_COUNT) >> 16));
- printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
+ printk(KERN_INFO DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
readl(host->ioaddr + SDHCI_ARGUMENT),
readl(host->ioaddr + SDHCI_TRANSFER_MODE));
- printk(KERN_DEBUG DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n",
+ printk(KERN_INFO DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n",
readl(host->ioaddr + SDHCI_PRESENT_STATE),
readl(host->ioaddr + SDHCI_HOST_CONTROL));
- printk(KERN_DEBUG DRIVER_NAME ": Clock: 0x%08x\n",
+ printk(KERN_INFO DRIVER_NAME ": Clock: 0x%08x\n",
readl(host->ioaddr + SDHCI_CLOCK_CONTROL));
- printk(KERN_DEBUG DRIVER_NAME ": Int stat: 0x%08x\n",
+ printk(KERN_INFO DRIVER_NAME ": Int stat: 0x%08x\n",
readl(host->ioaddr + SDHCI_INT_STATUS));
- printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
+ printk(KERN_INFO DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
readl(host->ioaddr + SDHCI_INT_ENABLE),
readl(host->ioaddr + SDHCI_SIGNAL_ENABLE));
- printk(KERN_DEBUG DRIVER_NAME ": Caps: 0x%08x\n",
+ printk(KERN_INFO DRIVER_NAME ": Caps: 0x%08x\n",
readl(host->ioaddr + SDHCI_CAPABILITIES));
- printk(KERN_DEBUG DRIVER_NAME
+ printk(KERN_INFO DRIVER_NAME
": ===========================================\n");
}
@@ -506,6 +506,30 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
host->flags &= ~SDHCI_REQ_USE_DMA;
}
+ if (cpu_is_mx25() && (data->blksz * data->blocks < 0x10)) {
+ host->flags &= ~SDHCI_REQ_USE_DMA;
+ DBG("Reverting to PIO in small data transfer.\n");
+ writel(readl(host->ioaddr + SDHCI_INT_ENABLE)
+ | SDHCI_INT_DATA_AVAIL
+ | SDHCI_INT_SPACE_AVAIL,
+ host->ioaddr + SDHCI_INT_ENABLE);
+ writel(readl(host->ioaddr + SDHCI_SIGNAL_ENABLE)
+ | SDHCI_INT_DATA_AVAIL
+ | SDHCI_INT_SPACE_AVAIL,
+ host->ioaddr + SDHCI_SIGNAL_ENABLE);
+ } else if (cpu_is_mx25() && (host->flags & SDHCI_USE_DMA)) {
+ host->flags |= SDHCI_REQ_USE_DMA;
+ DBG("Reverting to DMA in large data transfer.\n");
+ writel(readl(host->ioaddr + SDHCI_INT_ENABLE)
+ & ~(SDHCI_INT_DATA_AVAIL
+ | SDHCI_INT_SPACE_AVAIL),
+ host->ioaddr + SDHCI_INT_ENABLE);
+ writel(readl(host->ioaddr + SDHCI_SIGNAL_ENABLE)
+ & ~(SDHCI_INT_DATA_AVAIL
+ | SDHCI_INT_SPACE_AVAIL),
+ host->ioaddr + SDHCI_SIGNAL_ENABLE);
+ }
+
if (host->flags & SDHCI_REQ_USE_DMA) {
int i;
struct scatterlist *tsg;
@@ -644,7 +668,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
WARN_ON(host->cmd);
/* Wait max 10 ms */
- timeout = 5000;
+ timeout = 500;
mask = SDHCI_CMD_INHIBIT;
if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
@@ -695,7 +719,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
mode |= SDHCI_TRNS_READ;
else
mode &= ~SDHCI_TRNS_READ;
- if (host->flags & SDHCI_USE_DMA)
+ if (host->flags & SDHCI_REQ_USE_DMA)
mode |= SDHCI_TRNS_DMA;
if (host->flags & SDHCI_USE_EXTERNAL_DMA)
DBG("Prepare data completely in %s transfer mode.\n",
@@ -727,6 +751,11 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
flags |= SDHCI_CMD_DATA;
mode |= SDHCI_MAKE_CMD(cmd->opcode, flags);
+ if (host->mmc->ios.bus_width & MMC_BUS_WIDTH_DDR) {
+ /* Eanble the DDR mode */
+ mode |= SDHCI_TRNS_DDR_EN;
+ } else
+ mode &= ~SDHCI_TRNS_DDR_EN;
DBG("Complete sending cmd, transfer mode would be 0x%x.\n", mode);
writel(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
}
@@ -775,6 +804,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
int clk_rate = 0;
u32 clk;
unsigned long timeout;
+ struct mmc_ios ios = host->mmc->ios;
if (clock == 0) {
goto out;
@@ -784,17 +814,21 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
host->plat_data->clk_flg = 1;
}
}
- if (clock == host->clock)
+
+ if (clock == host->clock && !(ios.bus_width & MMC_BUS_WIDTH_DDR))
return;
clk_rate = clk_get_rate(host->clk);
clk = readl(host->ioaddr + SDHCI_CLOCK_CONTROL) & ~SDHCI_CLOCK_MASK;
- if (!cpu_is_mx53())
+ if (cpu_is_mx53() || cpu_is_mx50())
+ writel(clk | SDHCI_CLOCK_SDCLKFS1,
+ host->ioaddr + SDHCI_CLOCK_CONTROL);
+ else
writel(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
if (clock == host->min_clk)
prescaler = 16;
- else if (cpu_is_mx53())
+ else if (cpu_is_mx53() || cpu_is_mx50())
prescaler = 1;
else
prescaler = 0;
@@ -820,6 +854,21 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
DBG("prescaler = 0x%x, divider = 0x%x\n", prescaler, div);
clk |= (prescaler << 8) | (div << 4);
+ if (host->plat_data->clk_always_on
+ | (host->mmc->card && mmc_card_sdio(host->mmc->card)))
+ clk |= SDHCI_CLOCK_PER_EN | SDHCI_CLOCK_HLK_EN
+ | SDHCI_CLOCK_IPG_EN;
+ else
+ clk &= ~(SDHCI_CLOCK_PER_EN | SDHCI_CLOCK_HLK_EN
+ | SDHCI_CLOCK_IPG_EN);
+
+ /* Configure the clock delay line */
+ if ((host->plat_data->vendor_ver >= ESDHC_VENDOR_V3)
+ && host->plat_data->dll_override_en)
+ writel((host->plat_data->dll_delay_cells << 10)
+ | DLL_CTRL_SLV_OVERRIDE,
+ host->ioaddr + SDHCI_DLL_CONTROL);
+
/* Configure the clock control register */
clk |=
(readl(host->ioaddr + SDHCI_CLOCK_CONTROL) & (~SDHCI_CLOCK_MASK));
@@ -830,7 +879,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
host->ioaddr + SDHCI_CLOCK_CONTROL);
/* Wait max 10 ms */
- timeout = 5000;
+ timeout = 500;
while (timeout > 0) {
timeout--;
udelay(20);
@@ -933,8 +982,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
u32 tmp;
mxc_dma_device_t dev_id = 0;
- DBG("%s: clock %u, bus %lu, power %u, vdd %u\n", DRIVER_NAME,
- ios->clock, 1UL << ios->bus_width, ios->power_mode, ios->vdd);
+ DBG("%s: clock %u, bus %u, power %u, vdd %u\n", DRIVER_NAME,
+ ios->clock, ios->bus_width, ios->power_mode, ios->vdd);
host = mmc_priv(mmc);
@@ -1000,10 +1049,10 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
tmp = readl(host->ioaddr + SDHCI_HOST_CONTROL);
- if (ios->bus_width == MMC_BUS_WIDTH_4) {
+ if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_4) {
tmp &= ~SDHCI_CTRL_8BITBUS;
tmp |= SDHCI_CTRL_4BITBUS;
- } else if (ios->bus_width == MMC_BUS_WIDTH_8) {
+ } else if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_8) {
tmp &= ~SDHCI_CTRL_4BITBUS;
tmp |= SDHCI_CTRL_8BITBUS;
} else if (ios->bus_width == MMC_BUS_WIDTH_1) {
@@ -1044,7 +1093,7 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
{
struct sdhci_host *host;
unsigned long flags;
- u32 ier, prot, clk, present;
+ u32 ier, prot, present;
host = mmc_priv(mmc);
@@ -1057,19 +1106,12 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
if (--(host->sdio_enable))
goto exit_unlock;
}
- /* Enable the clock */
- if (!host->plat_data->clk_flg) {
- clk_enable(host->clk);
- host->plat_data->clk_flg = 1;
- }
- ier = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE);
+
+ ier = readl(host->ioaddr + SDHCI_INT_ENABLE);
prot = readl(host->ioaddr + SDHCI_HOST_CONTROL);
- clk = readl(host->ioaddr + SDHCI_CLOCK_CONTROL);
if (enable) {
ier |= SDHCI_INT_CARD_INT;
- prot |= SDHCI_CTRL_D3CD;
- clk |= SDHCI_CLOCK_PER_EN | SDHCI_CLOCK_IPG_EN;
present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
if ((present & SDHCI_CARD_INT_MASK) != SDHCI_CARD_INT_ID)
writel(SDHCI_INT_CARD_INT,
@@ -1077,12 +1119,24 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
} else {
ier &= ~SDHCI_INT_CARD_INT;
prot &= ~SDHCI_CTRL_D3CD;
- clk &= ~(SDHCI_CLOCK_PER_EN | SDHCI_CLOCK_IPG_EN);
}
writel(prot, host->ioaddr + SDHCI_HOST_CONTROL);
+ writel(ier, host->ioaddr + SDHCI_INT_ENABLE);
writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE);
- writel(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
+
+ /*
+ * Using D3CD to manually driver the HW to re-sample the SDIO interrupt
+ * on bus one more time to guarantee the SDIO interrupt signal sent
+ * from card during the interrupt signal disabled period will not
+ * be lost.
+ */
+ prot |= SDHCI_CTRL_CDSS;
+ writel(prot, host->ioaddr + SDHCI_HOST_CONTROL);
+ prot &= ~SDHCI_CTRL_D3CD;
+ writel(prot, host->ioaddr + SDHCI_HOST_CONTROL);
+ prot |= SDHCI_CTRL_D3CD;
+ writel(prot, host->ioaddr + SDHCI_HOST_CONTROL);
mmiowb();
exit_unlock:
@@ -1208,7 +1262,7 @@ static void sdhci_tasklet_finish(unsigned long param)
* The root cause is that the ROM code don't ensure
* the SD/MMC clk is running when boot system.
* */
- if (!machine_is_mx35_3ds() && req_done && host->plat_data->clk_flg &&
+ if (req_done && host->plat_data->clk_flg &&
!(host->mmc && host->mmc->card && mmc_card_sdio(host->mmc->card))) {
clk_disable(host->clk);
host->plat_data->clk_flg = 0;
@@ -1786,8 +1840,10 @@ static int __devinit sdhci_probe_slot(struct platform_device
/* Get the SDHC clock from clock system APIs */
host->clk = clk_get(&pdev->dev, mmc_plat->clock_mmc);
- if (NULL == host->clk)
+ if (NULL == host->clk) {
printk(KERN_ERR "MXC MMC can't get clock.\n");
+ goto out1;
+ }
DBG("SDHC:%d clock:%lu\n", pdev->id, clk_get_rate(host->clk));
host->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -2001,9 +2057,6 @@ static int __devinit sdhci_probe_slot(struct platform_device
}
mxc_dma_callback_set(host->dma, sdhci_dma_irq, (void *)host);
}
-#ifdef CONFIG_MMC_DEBUG
- sdhci_dumpregs(host);
-#endif
mmiowb();
diff --git a/drivers/mmc/host/mx_sdhci.h b/drivers/mmc/host/mx_sdhci.h
index 0bd79934952e..83d02975ecd1 100644
--- a/drivers/mmc/host/mx_sdhci.h
+++ b/drivers/mmc/host/mx_sdhci.h
@@ -2,7 +2,6 @@
* linux/drivers/mmc/host/mx_sdhci.h - Secure Digital Host
* Controller Interface driver
*
- * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
* Copyright (C) 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -28,6 +27,7 @@
#define SDHCI_TRNS_DMA 0x00000001
#define SDHCI_TRNS_BLK_CNT_EN 0x00000002
#define SDHCI_TRNS_ACMD12 0x00000004
+#define SDHCI_TRNS_DDR_EN 0x00000008
#define SDHCI_TRNS_READ 0x00000010
#define SDHCI_TRNS_MULTI 0x00000020
#define SDHCI_TRNS_DPSEL 0x00200000
@@ -69,6 +69,7 @@
#define SDHCI_CTRL_4BITBUS 0x00000002
#define SDHCI_CTRL_8BITBUS 0x00000004
#define SDHCI_CTRL_HISPD 0x00000004
+#define SDHCI_CTRL_CDSS 0x80
#define SDHCI_CTRL_DMA_MASK 0x18
#define SDHCI_CTRL_SDMA 0x00
#define SDHCI_CTRL_ADMA1 0x08
@@ -95,6 +96,7 @@
#define SDHCI_CLOCK_PER_EN 0x00000004
#define SDHCI_CLOCK_HLK_EN 0x00000002
#define SDHCI_CLOCK_IPG_EN 0x00000001
+#define SDHCI_CLOCK_SDCLKFS1 0x00000100
#define SDHCI_CLOCK_MASK 0x0000FFFF
#define SDHCI_TIMEOUT_CONTROL 0x2E
@@ -188,6 +190,18 @@
#define SDHCI_ADMA_ADDRESS 0x58
/* 60-FB reserved */
+#define SDHCI_DLL_CONTROL 0x60
+#define DLL_CTRL_ENABLE 0x00000001
+#define DLL_CTRL_RESET 0x00000002
+#define DLL_CTRL_SLV_FORCE_UPD 0x00000004
+#define DLL_CTRL_SLV_OVERRIDE 0x00000200
+#define DLL_CTRL_SLV_DLY_TAR 0x00000000
+#define DLL_CTRL_SLV_UP_INT 0x00200000
+#define DLL_CTRL_REF_UP_INT 0x20000000
+
+#define SDHCI_DLL_STATUS 0x64
+#define DLL_STS_SLV_LOCK 0x00000001
+#define DLL_STS_REF_LOCK 0x00000002
/* ADMA Addr Descriptor Attribute Filed */
enum {
@@ -207,6 +221,7 @@ enum {
#define SDHCI_SPEC_100 0
#define SDHCI_SPEC_200 1
#define ESDHC_VENDOR_V22 0x12
+#define ESDHC_VENDOR_V3 0x13
struct sdhci_chip;
diff --git a/drivers/mmc/host/mxc_mmc.c b/drivers/mmc/host/mxc_mmc.c
index 980dc98c9b5f..9cb492f40145 100644
--- a/drivers/mmc/host/mxc_mmc.c
+++ b/drivers/mmc/host/mxc_mmc.c
@@ -13,7 +13,7 @@
*/
/*
- * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -1232,7 +1232,7 @@ static int mxcmci_probe(struct platform_device *pdev)
mmc->f_max = mmc_plat->max_clk;
mmc->max_req_size = 32 * 1024;
mmc->max_seg_size = mmc->max_req_size;
- mmc->max_blk_count = 65536;
+ mmc->max_blk_count = 32;
spin_lock_init(&host->lock);
host->mmc = mmc;
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index c60352247c49..b7210b7d7af3 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -49,7 +49,7 @@
#define MXS_MMC_DETECT_TIMEOUT (HZ/2)
/* Max value supported for XFER_COUNT */
-#define SSP_BUFFER_SIZE (65536)
+#define SSP_BUFFER_SIZE (65535)
#ifndef BF
#define BF(value, field) (((value) << BP_##field) & BM_##field)
@@ -93,6 +93,9 @@
#define BF_SSP_BLOCK_SIZE_BLOCK_SIZE(v) \
(((v) << 16) & BM_SSP_BLOCK_SIZE_BLOCK_SIZE)
#endif
+#ifndef BM_SSP_CMD0_DBL_DATA_RATE_EN
+#define BM_SSP_CMD0_DBL_DATA_RATE_EN 0x02000000
+#endif
struct mxs_mmc_host {
struct device *dev;
@@ -159,6 +162,7 @@ static inline int mxs_mmc_is_plugged(struct mxs_mmc_host *host)
return !(status & BM_SSP_STATUS_CARD_DETECT);
}
+static void mxs_mmc_reset(struct mxs_mmc_host *host);
/* Card detection polling function */
static void mxs_mmc_detect_poll(unsigned long arg)
{
@@ -167,6 +171,8 @@ static void mxs_mmc_detect_poll(unsigned long arg)
card_status = mxs_mmc_is_plugged(host);
if (card_status != host->present) {
+ /* Reset MMC block */
+ mxs_mmc_reset(host);
host->present = card_status;
mmc_detect_change(host->mmc, 0);
}
@@ -183,6 +189,12 @@ static void mxs_mmc_detect_poll(unsigned long arg)
BM_SSP_CTRL1_RECV_TIMEOUT_IRQ | \
BM_SSP_CTRL1_FIFO_OVERRUN_IRQ)
+#define MXS_MMC_ERR_BITS (BM_SSP_CTRL1_RESP_ERR_IRQ | \
+ BM_SSP_CTRL1_RESP_TIMEOUT_IRQ | \
+ BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | \
+ BM_SSP_CTRL1_DATA_CRC_IRQ | \
+ BM_SSP_CTRL1_RECV_TIMEOUT_IRQ)
+
/* SSP DMA interrupt handler */
static irqreturn_t mmc_irq_handler(int irq, void *dev_id)
{
@@ -198,19 +210,17 @@ static irqreturn_t mmc_irq_handler(int irq, void *dev_id)
/* STOP the dma transfer here. */
mxs_dma_cooked(host->dmach, NULL);
}
- host->status =
- __raw_readl(host->ssp_base + HW_SSP_STATUS);
- if (host->cmd) /* else it is a bogus interrupt */
- complete(&host->dma_done);
+ if ((irq == host->dmairq) || (c1 & MXS_MMC_ERR_BITS))
+ if (host->cmd) {
+ host->status =
+ __raw_readl(host->ssp_base + HW_SSP_STATUS);
+ complete(&host->dma_done);
+ }
- if ((c1 & BM_SSP_CTRL1_SDIO_IRQ) && (c1 & BM_SSP_CTRL1_SDIO_IRQ_EN)) {
- __raw_writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, host->ssp_base + \
- HW_SSP_CTRL0_CLR);
- __raw_writel(BM_SSP_CTRL1_SDIO_IRQ_EN, host->ssp_base + \
- HW_SSP_CTRL1_CLR);
+ if ((c1 & BM_SSP_CTRL1_SDIO_IRQ) && (c1 & BM_SSP_CTRL1_SDIO_IRQ_EN))
mmc_signal_sdio_irq(host->mmc);
- }
+
return IRQ_HANDLED;
}
@@ -239,6 +249,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host)
{
struct mmc_command *cmd = host->cmd;
struct mxs_dma_desc *dma_desc = host->dma_desc;
+ unsigned long flags;
dma_desc->cmd.cmd.bits.command = NO_DMA_XFER;
dma_desc->cmd.cmd.bits.irq = 1;
@@ -255,7 +266,8 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host)
if (host->sdio_irq_en) {
dma_desc->cmd.pio_words[0] |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
- dma_desc->cmd.pio_words[1] |= BM_SSP_CMD0_CONT_CLKING_EN;
+ dma_desc->cmd.pio_words[1] |= BM_SSP_CMD0_CONT_CLKING_EN \
+ | BM_SSP_CMD0_SLOW_CLKING_EN;
}
init_completion(&host->dma_done);
@@ -265,6 +277,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host)
dev_dbg(host->dev, "%s start DMA.\n", __func__);
if (mxs_dma_enable(host->dmach) < 0)
dev_err(host->dev, "mmc_dma_enable failed\n");
+
wait_for_completion(&host->dma_done);
cmd->error = mxs_mmc_cmd_error(host->status);
@@ -273,6 +286,7 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host)
dev_dbg(host->dev, "Command error 0x%x\n", cmd->error);
mxs_dma_reset(host->dmach);
}
+ mxs_dma_disable(host->dmach);
}
/* Send the ac command to the device */
@@ -284,6 +298,7 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host)
u32 ssp_ctrl0;
u32 ssp_cmd0;
u32 ssp_cmd1;
+ unsigned long flags;
ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ?
0 : BM_SSP_CTRL0_IGNORE_CRC;
@@ -305,7 +320,8 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host)
if (host->sdio_irq_en) {
ssp_ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
- ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN;
+ ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN \
+ | BM_SSP_CMD0_SLOW_CLKING_EN;
}
dma_desc->cmd.pio_words[0] = ssp_ctrl0;
@@ -356,6 +372,7 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host)
dev_dbg(host->dev, "Command error 0x%x\n", cmd->error);
mxs_dma_reset(host->dmach);
}
+ mxs_dma_disable(host->dmach);
}
/* Copy data between sg list and dma buffer */
@@ -451,6 +468,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
u32 data_size = cmd->data->blksz * cmd->data->blocks;
u32 log2_block_size;
+ unsigned long flags;
ignore_crc = mmc_resp_type(cmd) & MMC_RSP_CRC ? 0 : 1;
resp = mmc_resp_type(cmd) & MMC_RSP_PRESENT ? 1 : 0;
@@ -540,6 +558,9 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
dev_dbg(host->dev, "%s blksz is 0x%x.\n", __func__, log2_block_size);
if (ssp_ver_major > 3) {
+ /* Configure the CMD0 */
+ ssp_cmd0 = BF(cmd->opcode, SSP_CMD0_CMD);
+
/* Configure the BLOCK SIZE and BLOCK COUNT */
if ((1<<log2_block_size) != cmd->data->blksz) {
BUG_ON(cmd->data->blocks > 1);
@@ -548,20 +569,32 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
val = BF(log2_block_size, SSP_BLOCK_SIZE_BLOCK_SIZE) |
BF(cmd->data->blocks - 1, SSP_BLOCK_SIZE_BLOCK_COUNT);
__raw_writel(val, host->ssp_base + HW_SSP_BLOCK_SIZE);
- }
- /* Configure the CMD0 */
- ssp_cmd0 = BF(cmd->opcode, SSP_CMD0_CMD);
- } else
- ssp_cmd0 =
- BF(log2_block_size, SSP_BLOCK_SIZE_BLOCK_SIZE) |
- BF(cmd->opcode, SSP_CMD0_CMD) |
- BF(cmd->data->blocks - 1, SSP_BLOCK_SIZE_BLOCK_COUNT);
+ if (host->mmc->ios.bus_width & MMC_BUS_WIDTH_DDR)
+ /* Enable the DDR mode */
+ ssp_cmd0 |= BM_SSP_CMD0_DBL_DATA_RATE_EN;
+ else
+ ssp_cmd0 &= ~BM_SSP_CMD0_DBL_DATA_RATE_EN;
+ }
+ } else {
+ if ((1<<log2_block_size) != cmd->data->blksz) {
+ BUG_ON(cmd->data->blocks > 1);
+ ssp_cmd0 =
+ BF(0, SSP_BLOCK_SIZE_BLOCK_SIZE) |
+ BF(cmd->opcode, SSP_CMD0_CMD) |
+ BF(0, SSP_BLOCK_SIZE_BLOCK_COUNT);
+ } else
+ ssp_cmd0 =
+ BF(log2_block_size, SSP_BLOCK_SIZE_BLOCK_SIZE) |
+ BF(cmd->opcode, SSP_CMD0_CMD) |
+ BF(cmd->data->blocks - 1, SSP_BLOCK_SIZE_BLOCK_COUNT);
+ }
if (host->sdio_irq_en) {
ssp_ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
- ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN;
+ ssp_cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN \
+ | BM_SSP_CMD0_SLOW_CLKING_EN;
}
- if (cmd->opcode == 12)
+ if ((cmd->opcode == 12) || (cmd->opcode == 53))
ssp_cmd0 |= BM_SSP_CMD0_APPEND_8CYC;
ssp_cmd1 = BF(cmd->arg, SSP_CMD1_CMD_ARG);
@@ -628,6 +661,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
dev_dbg(host->dev, "Transferred %u bytes\n",
cmd->data->bytes_xfered);
}
+ mxs_dma_disable(host->dmach);
}
/* Begin sedning a command to the card */
@@ -672,6 +706,13 @@ static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
dev_dbg(host->dev, "MMC request\n");
+ if (!host->present) {
+ mrq->cmd->error = -ETIMEDOUT;
+ mmc_request_done(mmc, mrq);
+ return;
+ }
+
+ BUG_ON(host->mrq != NULL);
host->mrq = mrq;
mxs_mmc_start_cmd(host, mrq->cmd);
@@ -777,9 +818,9 @@ static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
dev_warn(host->dev,
"Platform does not support CMD pin pullup control\n");
- if (ios->bus_width == MMC_BUS_WIDTH_8)
+ if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_8)
host->bus_width = 2;
- else if (ios->bus_width == MMC_BUS_WIDTH_4)
+ else if ((ios->bus_width & ~MMC_BUS_WIDTH_DDR) == MMC_BUS_WIDTH_4)
host->bus_width = 1;
else
host->bus_width = 0;
@@ -851,7 +892,6 @@ static void mxs_mmc_reset(struct mxs_mmc_host *host)
/* Configure SSP Control Register 1 */
ssp_ctrl1 =
BM_SSP_CTRL1_DMA_ENABLE |
- BM_SSP_CTRL1_POLARITY |
BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN |
BM_SSP_CTRL1_DATA_CRC_IRQ_EN |
BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN |
diff --git a/drivers/mtd/devices/mxc_dataflash.c b/drivers/mtd/devices/mxc_dataflash.c
index ab75d743a05b..0ed701d6778c 100644
--- a/drivers/mtd/devices/mxc_dataflash.c
+++ b/drivers/mtd/devices/mxc_dataflash.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
* (c) 2005 MontaVista Software, Inc.
*
* This code is based on mtd_dataflash.c by adding FSL spi access.
@@ -22,10 +22,10 @@
#include <linux/err.h>
#include <linux/spi/spi.h>
-#include <linux/spi/flash.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <asm/mach/flash.h>
/*
* DataFlash is a kind of SPI flash. Most AT45 chips have two buffers in
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 8f1eebf8d3b3..1a85f6d5543b 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -434,49 +434,9 @@ config MXC_NAND_LOW_LEVEL_ERASE
This enables the erase of whole NAND flash. By
default low level erase operation is disabled.
-config MTD_NAND_GPMI_LBA
- tristate "GPMI LBA NAND driver"
- depends on MTD_NAND && ARCH_STMP3XXX
- help
- Enables support of LBA devices on GPMI on 37xx/378x SigmaTel
- boards
-
-config MTD_NAND_GPMI
- tristate "GPMI NAND driver"
- depends on MTD_NAND && ARCH_STMP3XXX && !MTD_NAND_GPMI_LBA
- help
- Enables support of NAND devices on GPMI on 37xx/378x SigmaTel
- boards
-
-config MTD_NAND_GPMI_SYSFS_ENTRIES
- bool "Create /sys entries for GPMI device"
- depends on MTD_NAND_GPMI
- help
- Check this to enable /sys entries for GPMI devices
-
-config MTD_NAND_GPMI_BCH
- bool "Enable BCH HWECC"
- depends on MTD_NAND_GPMI
- depends on ARCH_STMP378X
- default y
- help
- Check this to enable /sys entries for GPMI devices
-
-config MTD_NAND_GPMI_TA1
- bool "Support for TA1 NCB format (Hamming code 22,16)"
- depends on MTD_NAND_GPMI
- depends on ARCH_STMP378X
- default y
-
-config MTD_NAND_GPMI_TA3
- bool "Support for TA3 NCB format (Hamming code 13,8)"
- depends on MTD_NAND_GPMI
- depends on ARCH_STMP378X
- default y
-
-config MTD_NAND_GPMI1
- tristate "GPMI NAND Flash driver"
- depends on MTD_NAND && ARCH_MX28
+config MTD_NAND_GPMI_NFC
+ tristate "GPMI NAND Flash Controller driver"
+ depends on MTD_NAND && (ARCH_MX23 || ARCH_MX28 || ARCH_MX50)
help
Enables NAND Flash support.
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 730f5db16e1d..2245a8df441b 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -41,9 +41,7 @@ obj-$(CONFIG_MTD_NAND_IMX_NFC) += imx_nfc.o
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
obj-$(CONFIG_MTD_NAND_MXC_V2) += mxc_nd2.o nand_device_info.o
obj-$(CONFIG_MTD_NAND_MXC_V3) += mxc_nd2.o nand_device_info.o
-obj-$(CONFIG_MTD_NAND_GPMI) += gpmi/ nand_device_info.o
-obj-$(CONFIG_MTD_NAND_GPMI1) += gpmi1/ nand_device_info.o
-obj-$(CONFIG_MTD_NAND_GPMI_LBA) += lba/
+obj-$(CONFIG_MTD_NAND_GPMI_NFC) += gpmi-nfc/ nand_device_info.o
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
diff --git a/drivers/mtd/nand/mxc_nd2.c b/drivers/mtd/nand/mxc_nd2.c
index 46e6380fe462..80533ac42e9c 100644
--- a/drivers/mtd/nand/mxc_nd2.c
+++ b/drivers/mtd/nand/mxc_nd2.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -32,12 +32,15 @@
/* Global address Variables */
static void __iomem *nfc_axi_base, *nfc_ip_base;
+static int nfc_irq;
struct mxc_mtd_s {
struct mtd_info mtd;
struct nand_chip nand;
struct mtd_partition *parts;
struct device *dev;
+ int disable_bi_swap; /* disable bi swap */
+ int clk_active;
};
static struct mxc_mtd_s *mxc_nand_data;
@@ -117,6 +120,49 @@ static const char *part_probes[] = {
static wait_queue_head_t irq_waitq;
+#if 0
+static void nand_page_dump(struct mtd_info *mtd, u8 *dbuf, u8* obuf)
+{
+ int i;
+
+ if (dbuf != NULL) {
+ printk("\nData buffer:");
+ for (i = 0; i < mtd->writesize; i++) {
+ if (!(i % 8)) printk("\n%03x: ", i);
+ printk("%02x ", dbuf[i]);
+ }
+ }
+ printk("\n");
+ if (obuf != NULL) {
+ printk("\nOOB buffer:");
+ for (i = 0; i < mtd->oobsize; i++) {
+ if (!(i % 8)) printk("\n%02x: ", i);
+ printk("%02x ", obuf[i]);
+ }
+ }
+ printk("\n");
+}
+#endif
+
+#ifdef CONFIG_MXC_NAND_SWAP_BI
+#define PART_UBOOT_SIZE 0xc0000
+#define SKIP_SWAP_BI_MAX_PAGE (PART_UBOOT_SIZE / 0x800)
+inline int skip_swap_bi(int page)
+{
+ /**
+ * Seems that the boot code of the i.mx515 rom is not able to
+ * boot from a nand flash when the data has been written swapping
+ * the bad block byte. Avoid doing that (the swapping) when
+ * programming U-Boot into the flash.
+ */
+ if (page < SKIP_SWAP_BI_MAX_PAGE)
+ return 1;
+ return 0;
+}
+#else
+inline int skip_swap_bi(int page_addr) { return 1; }
+#endif
+
static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
{
/* Disable Interuupt */
@@ -126,6 +172,30 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void mxc_nand_bi_swap(struct mtd_info *mtd, int page_addr)
+{
+ u16 ma, sa, nma, nsa;
+
+ if (!IS_LARGE_PAGE_NAND)
+ return;
+
+ /* Disable bi swap if the user set disable_bi_swap at sys entry */
+ if (mxc_nand_data->disable_bi_swap)
+ return;
+
+ if (skip_swap_bi(page_addr))
+ return;
+
+ ma = __raw_readw(BAD_BLK_MARKER_MAIN);
+ sa = __raw_readw(BAD_BLK_MARKER_SP);
+
+ nma = (ma & 0xFF00) | (sa >> 8);
+ nsa = (sa & 0x00FF) | (ma << 8);
+
+ __raw_writew(nma, BAD_BLK_MARKER_MAIN);
+ __raw_writew(nsa, BAD_BLK_MARKER_SP);
+}
+
static void nfc_memcpy(void *dest, void *src, int len)
{
u8 *d = dest;
@@ -287,6 +357,7 @@ static void auto_cmd_interleave(struct mtd_info *mtd, u16 cmd)
/* data transfer */
memcpy(MAIN_AREA0, dbuf, dlen);
copy_spare(mtd, obuf, SPARE_AREA0, olen, false);
+ mxc_nand_bi_swap(mtd, page_addr - 1);
/* update the value */
dbuf += dlen;
@@ -316,6 +387,7 @@ static void auto_cmd_interleave(struct mtd_info *mtd, u16 cmd)
mxc_check_ecc_status(mtd);
/* data transfer */
+ mxc_nand_bi_swap(mtd, page_addr - 1);
memcpy(dbuf, MAIN_AREA0, dlen);
copy_spare(mtd, obuf, SPARE_AREA0, olen, true);
@@ -558,10 +630,7 @@ static int mxc_check_ecc_status(struct mtd_info *mtd)
u32 ecc_stat, err;
int no_subpages = 1;
int ret = 0;
- u8 ecc_bit_mask, err_limit;
-
- ecc_bit_mask = (IS_4BIT_ECC ? 0x7 : 0xf);
- err_limit = (IS_4BIT_ECC ? 0x4 : 0x8);
+ u8 ecc_bit_mask = 0xf;
no_subpages = mtd->writesize >> 9;
@@ -570,7 +639,7 @@ static int mxc_check_ecc_status(struct mtd_info *mtd)
ecc_stat = GET_NFC_ECC_STATUS();
do {
err = ecc_stat & ecc_bit_mask;
- if (err > err_limit) {
+ if (err == ecc_bit_mask) {
mtd->ecc_stats.failed++;
printk(KERN_WARNING "UnCorrectable RS-ECC Error\n");
return -1;
@@ -580,8 +649,7 @@ static int mxc_check_ecc_status(struct mtd_info *mtd)
ecc_stat >>= 4;
} while (--no_subpages);
- mtd->ecc_stats.corrected += ret;
- pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
+ pr_debug("Correctable ECC Error(%d)\n", ret);
return ret;
}
@@ -774,6 +842,30 @@ static int mxc_nand_verify_buf(struct mtd_info *mtd, const u_char * buf,
}
/*!
+ * This function will enable NFC clock
+ *
+ */
+static inline void mxc_nand_clk_enable(void)
+{
+ if (!mxc_nand_data->clk_active) {
+ clk_enable(nfc_clk);
+ mxc_nand_data->clk_active = 1;
+ }
+}
+
+/*!
+ * This function will disable NFC clock
+ *
+ */
+static inline void mxc_nand_clk_disable(void)
+{
+ if (mxc_nand_data->clk_active) {
+ clk_disable(nfc_clk);
+ mxc_nand_data->clk_active = 0;
+ }
+}
+
+/*!
* This function is used by upper layer for select and deselect of the NAND
* chip
*
@@ -786,13 +878,14 @@ static void mxc_nand_select_chip(struct mtd_info *mtd, int chip)
switch (chip) {
case -1:
/* Disable the NFC clock */
- clk_disable(nfc_clk);
+ mxc_nand_clk_disable();
+
break;
- case 0 ... 7:
+ case 0 ... NFC_GET_MAXCHIP_SP():
/* Enable the NFC clock */
- clk_enable(nfc_clk);
-
+ mxc_nand_clk_enable();
NFC_SET_NFC_ACTIVE_CS(chip);
+
break;
default:
@@ -930,6 +1023,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
*/
nfc_memcpy(MAIN_AREA0, data_buf, mtd->writesize);
copy_spare(mtd, oob_buf, SPARE_AREA0, mtd->oobsize, false);
+ mxc_nand_bi_swap(mtd, page_addr);
#endif
if (IS_LARGE_PAGE_NAND)
@@ -980,10 +1074,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
* byte alignment, so we can use
* memcpy safely
*/
+ mxc_nand_bi_swap(mtd, page_addr);
nfc_memcpy(data_buf, MAIN_AREA0, mtd->writesize);
copy_spare(mtd, oob_buf, SPARE_AREA0, mtd->oobsize, true);
#endif
-
break;
case NAND_CMD_READID:
@@ -1096,6 +1190,14 @@ static int mxc_nand_scan_bbt(struct mtd_info *mtd)
/* jffs2 not write oob */
mtd->flags &= ~MTD_OOB_WRITEABLE;
+ /* fix up the offset */
+ largepage_memorybased.offs = BAD_BLK_MARKER_OOB_OFFS;
+ /* keep compatible for bbt table with old soc */
+ if (cpu_is_mx53()) {
+ bbt_mirror_descr.offs = BAD_BLK_MARKER_OOB_OFFS + 2;
+ bbt_main_descr.offs = BAD_BLK_MARKER_OOB_OFFS + 2;
+ }
+
/* use flash based bbt */
this->bbt_td = &bbt_main_descr;
this->bbt_md = &bbt_mirror_descr;
@@ -1126,6 +1228,53 @@ static int mxc_nand_scan_bbt(struct mtd_info *mtd)
return nand_scan_bbt(mtd, this->badblock_pattern);
}
+static int mxc_get_resources(struct platform_device *pdev)
+{
+ struct resource *r;
+ int error = 0;
+
+#define MXC_NFC_NO_IP_REG \
+ (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx32() || cpu_is_mx35())
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ error = -ENXIO;
+ goto out_0;
+ }
+ nfc_axi_base = ioremap(r->start, resource_size(r));
+
+ if (!MXC_NFC_NO_IP_REG) {
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!r) {
+ error = -ENXIO;
+ goto out_1;
+ }
+ }
+ nfc_ip_base = ioremap(r->start, resource_size(r));
+
+ r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!r) {
+ error = -ENXIO;
+ goto out_2;
+ }
+ nfc_irq = r->start;
+
+ init_waitqueue_head(&irq_waitq);
+ error = request_irq(nfc_irq, mxc_nfc_irq, 0, "mxc_nd", NULL);
+ if (error)
+ goto out_3;
+
+ return 0;
+out_3:
+out_2:
+ if (!MXC_NFC_NO_IP_REG)
+ iounmap(nfc_ip_base);
+out_1:
+ iounmap(nfc_axi_base);
+out_0:
+ return error;
+}
+
static void mxc_nfc_init(void)
{
/* Disable interrupt */
@@ -1137,11 +1286,13 @@ static void mxc_nfc_init(void)
/* Unlock the internal RAM Buffer */
raw_write(NFC_SET_BLS(NFC_BLS_UNLCOKED), REG_NFC_BLS);
- /* Blocks to be unlocked */
- UNLOCK_ADDR(0x0, 0xFFFF);
+ if (!(cpu_is_mx53())) {
+ /* Blocks to be unlocked */
+ UNLOCK_ADDR(0x0, 0xFFFF);
- /* Unlock Block Command for given address range */
- raw_write(NFC_SET_WPC(NFC_WPC_UNLOCK), REG_NFC_WPC);
+ /* Unlock Block Command for given address range */
+ raw_write(NFC_SET_WPC(NFC_WPC_UNLOCK), REG_NFC_WPC);
+ }
/* Enable symetric mode by default except mx37TO1.0 */
if (!(cpu_is_mx37_rev(CHIP_REV_1_0) == 1))
@@ -1232,6 +1383,81 @@ int nand_scan_mid(struct mtd_info *mtd)
return 0;
}
+/*!
+ * show_device_disable_bi_swap()
+ * Shows the value of the 'disable_bi_swap' flag.
+ *
+ * @dev: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer that will receive a representation of the attribute.
+ */
+static ssize_t show_device_disable_bi_swap(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", mxc_nand_data->disable_bi_swap);
+}
+
+/*!
+ * store_device_disable_bi_swap()
+ * Sets the value of the 'disable_bi_swap' flag.
+ *
+ * @dev: The device of interest.
+ * @attr: The attribute of interest.
+ * @buf: A buffer containing a new attribute value.
+ * @size: The size of the buffer.
+ */
+static ssize_t store_device_disable_bi_swap(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ const char *p = buf;
+ unsigned long v;
+
+ /* Try to make sense of what arrived from user space. */
+
+ if (strict_strtoul(p, 0, &v) < 0)
+ return size;
+
+ if (v > 0)
+ v = 1;
+ mxc_nand_data->disable_bi_swap = v;
+ return size;
+
+}
+
+static DEVICE_ATTR(disable_bi_swap, 0644,
+ show_device_disable_bi_swap, store_device_disable_bi_swap);
+static struct device_attribute *device_attributes[] = {
+ &dev_attr_disable_bi_swap,
+};
+/*!
+ * manage_sysfs_files() - Creates/removes sysfs files for this device.
+ *
+ * @create: create/remove the sys entry.
+ */
+static void manage_sysfs_files(int create)
+{
+ struct device *dev = mxc_nand_data->dev;
+ int error;
+ unsigned int i;
+ struct device_attribute **attr;
+
+ for (i = 0, attr = device_attributes;
+ i < ARRAY_SIZE(device_attributes); i++, attr++) {
+
+ if (create) {
+ error = device_create_file(dev, *attr);
+ if (error) {
+ while (--attr >= device_attributes)
+ device_remove_file(dev, *attr);
+ return;
+ }
+ } else {
+ device_remove_file(dev, *attr);
+ }
+ }
+
+}
+
/*!
* This function is called during the driver binding process.
@@ -1249,8 +1475,10 @@ static int __init mxcnd_probe(struct platform_device *pdev)
struct flash_platform_data *flash = pdev->dev.platform_data;
int nr_parts = 0, err = 0;
- nfc_axi_base = IO_ADDRESS(NFC_AXI_BASE_ADDR);
- nfc_ip_base = IO_ADDRESS(NFC_BASE_ADDR);
+ /* get the resource */
+ err = mxc_get_resources(pdev);
+ if (err)
+ goto out;
/* init the nfc */
mxc_nfc_init();
@@ -1298,12 +1526,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
nfc_clk = clk_get(&pdev->dev, "nfc_clk");
clk_enable(nfc_clk);
-
- init_waitqueue_head(&irq_waitq);
- err = request_irq(MXC_INT_NANDFC, mxc_nfc_irq, 0, "mxc_nd", NULL);
- if (err) {
- goto out_1;
- }
+ mxc_nand_data->clk_active = 1;
if (hardware_ecc) {
this->ecc.read_page = mxc_nand_read_page;
@@ -1359,6 +1582,16 @@ static int __init mxcnd_probe(struct platform_device *pdev)
add_mtd_device(mtd);
}
+#ifdef CONFIG_MODULE_CCXMX51
+ {
+ extern u8 ccwmx51_swap_bi;
+ mxc_nand_data->disable_bi_swap = !ccwmx51_swap_bi;
+ pr_info("%sUsing swap BI (%x)\n", ccwmx51_swap_bi ? "" : "No ", ccwmx51_swap_bi);
+ }
+#endif
+ /* Create sysfs entries for this device. */
+ manage_sysfs_files(true);
+
platform_set_drvdata(pdev, mtd);
return 0;
@@ -1386,15 +1619,16 @@ static int __exit mxcnd_remove(struct platform_device *pdev)
if (flash->exit)
flash->exit();
+ manage_sysfs_files(false);
mxc_free_buf();
- clk_disable(nfc_clk);
+ mxc_nand_clk_disable();
clk_put(nfc_clk);
platform_set_drvdata(pdev, NULL);
if (mxc_nand_data) {
nand_release(mtd);
- free_irq(MXC_INT_NANDFC, NULL);
+ free_irq(nfc_irq, NULL);
kfree(mxc_nand_data);
}
@@ -1419,7 +1653,7 @@ static int mxcnd_suspend(struct platform_device *pdev, pm_message_t state)
DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND2 : NAND suspend\n");
/* Disable the NFC clock */
- clk_disable(nfc_clk);
+ mxc_nand_clk_disable();
return 0;
}
@@ -1438,7 +1672,7 @@ static int mxcnd_resume(struct platform_device *pdev)
DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND2 : NAND resume\n");
/* Enable the NFC clock */
- clk_enable(nfc_clk);
+ mxc_nand_clk_enable();
return 0;
}
diff --git a/drivers/mtd/nand/mxc_nd2.h b/drivers/mtd/nand/mxc_nd2.h
index ea128f6da41b..e8ef125ce8e7 100644
--- a/drivers/mtd/nand/mxc_nd2.h
+++ b/drivers/mtd/nand/mxc_nd2.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -32,16 +32,37 @@
#define IS_LARGE_PAGE_NAND ((mtd->writesize / num_of_interleave) > 512)
#define GET_NAND_OOB_SIZE (mtd->oobsize / num_of_interleave)
+#define GET_NAND_PAGE_SIZE (mtd->writesize / num_of_interleave)
#define NAND_PAGESIZE_2KB 2048
#define NAND_PAGESIZE_4KB 4096
+/*
+ * main area for bad block marker is in the last data section
+ * the spare area for swapped bad block marker is the second
+ * byte of last spare section
+ */
+#define NAND_SECTIONS (GET_NAND_PAGE_SIZE >> 9)
+#define NAND_OOB_PER_SECTION (((GET_NAND_OOB_SIZE / NAND_SECTIONS) >> 1) << 1)
+#define NAND_CHUNKS (GET_NAND_PAGE_SIZE / (512 + NAND_OOB_PER_SECTION))
+
+#define BAD_BLK_MARKER_MAIN_OFFS \
+ (GET_NAND_PAGE_SIZE - NAND_CHUNKS * NAND_OOB_PER_SECTION)
+
+#define BAD_BLK_MARKER_SP_OFFS (NAND_CHUNKS * SPARE_LEN)
+
+#define BAD_BLK_MARKER_OOB_OFFS (NAND_CHUNKS * NAND_OOB_PER_SECTION)
+
+#define BAD_BLK_MARKER_MAIN \
+ ((u32)MAIN_AREA0 + BAD_BLK_MARKER_MAIN_OFFS)
+
+#define BAD_BLK_MARKER_SP \
+ ((u32)SPARE_AREA0 + BAD_BLK_MARKER_SP_OFFS)
+
#ifdef CONFIG_ARCH_MXC_HAS_NFC_V3
/*
* For V3 NFC registers Definition
*/
-/* AXI Bus Mapped */
-#define NFC_AXI_BASE_ADDR MX51_NFC_BASE_ADDR_AXI
#if defined(CONFIG_ARCH_MXC_HAS_NFC_V3_1) /* mx37 */
#define MXC_INT_NANDFC MXC_INT_EMI
@@ -106,13 +127,6 @@
#define NFC_SPAS_WIDTH 8
#define NFC_SPAS_SHIFT 16
-#define IS_4BIT_ECC \
-( \
- cpu_is_mx51_rev(CHIP_REV_2_0) > 0 ? \
- !((raw_read(NFC_CONFIG2) & NFC_ECC_MODE_4) >> 6) : \
- ((raw_read(NFC_CONFIG2) & NFC_ECC_MODE_4) >> 6) \
-)
-
#define NFC_SET_SPAS(v) \
raw_write((((raw_read(NFC_CONFIG2) & \
NFC_FIELD_RESET(NFC_SPAS_WIDTH, NFC_SPAS_SHIFT)) | ((v) << 16))), \
@@ -120,24 +134,32 @@
#define NFC_SET_ECC_MODE(v) \
do { \
- if (cpu_is_mx51_rev(CHIP_REV_2_0) > 0) { \
+ if (cpu_is_mx53() > 0) { \
if ((v) == NFC_SPAS_218 || (v) == NFC_SPAS_112) \
raw_write(((raw_read(NFC_CONFIG2) & \
- NFC_ECC_MODE_MASK) | \
- NFC_ECC_MODE_4), NFC_CONFIG2); \
+ ~(3 << 6)) | \
+ NFC_ECC_MODE_16), NFC_CONFIG2); \
else \
raw_write(((raw_read(NFC_CONFIG2) & \
- NFC_ECC_MODE_MASK) & \
+ ~(3 << 6)) & \
+ NFC_ECC_MODE_4), NFC_CONFIG2); \
+ } else if (cpu_is_mx51_rev(CHIP_REV_2_0) > 0) { \
+ if ((v) == NFC_SPAS_218 || (v) == NFC_SPAS_112) \
+ raw_write(((raw_read(NFC_CONFIG2) & \
+ ~(1 << 6)) | \
NFC_ECC_MODE_8), NFC_CONFIG2); \
+ else \
+ raw_write(((raw_read(NFC_CONFIG2) & \
+ ~(1 << 6)) & \
+ ~NFC_ECC_MODE_8), NFC_CONFIG2); \
} else { \
if ((v) == NFC_SPAS_218 || (v) == NFC_SPAS_112) \
raw_write(((raw_read(NFC_CONFIG2) & \
- NFC_ECC_MODE_MASK) & \
- NFC_ECC_MODE_8), NFC_CONFIG2); \
+ ~(1 << 6))), NFC_CONFIG2); \
else \
raw_write(((raw_read(NFC_CONFIG2) & \
- NFC_ECC_MODE_MASK) | \
- NFC_ECC_MODE_4), NFC_CONFIG2); \
+ ~(1 << 6)) | \
+ NFC_ECC_MODE_8), NFC_CONFIG2); \
} \
} while (0)
@@ -151,7 +173,6 @@ do { \
} while(0)
#else
-#define IS_4BIT_ECC 1
#define NFC_SET_SPAS(v)
#define NFC_SET_ECC_MODE(v)
#define NFC_SET_NFMS(v) (NFMS |= (v))
@@ -292,9 +313,10 @@ do { \
#define NFC_WPC_RESET ~(7)
#if defined(CONFIG_ARCH_MXC_HAS_NFC_V3_1) || \
defined(CONFIG_ARCH_MXC_HAS_NFC_V3_2)
-#define NFC_ECC_MODE_4 (1 << 6)
-#define NFC_ECC_MODE_8 ~(1 << 6)
-#define NFC_ECC_MODE_MASK ~(1 << 6)
+#define NFC_ECC_MODE_4 (0x0 << 6)
+#define NFC_ECC_MODE_8 (0x1 << 6)
+#define NFC_ECC_MODE_14 (0x3 << 6)
+#define NFC_ECC_MODE_16 (0x3 << 6)
#define NFC_SPAS_16 8
#define NFC_SPAS_64 32
#define NFC_SPAS_128 64
@@ -454,7 +476,8 @@ do { \
NFC_SET_ST_CMD(0x70); \
raw_write(raw_read(NFC_CONFIG3) | NFC_NO_SDMA, NFC_CONFIG3); \
raw_write(raw_read(NFC_CONFIG3) | NFC_RBB_MODE, NFC_CONFIG3); \
- SET_NFC_DELAY_LINE(0); \
+ if (cpu_is_mx51()) \
+ SET_NFC_DELAY_LINE(0); \
} \
} while (0)
#endif
@@ -472,14 +495,13 @@ do { \
* For V1/V2 NFC registers Definition
*/
-#define NFC_AXI_BASE_ADDR 0x00
/*
* Addresses for NFC registers
*/
#ifdef CONFIG_ARCH_MXC_HAS_NFC_V2_1
-#define NFC_REG_BASE (nfc_ip_base + 0x1000)
+#define NFC_REG_BASE (nfc_axi_base + 0x1000)
#else
-#define NFC_REG_BASE nfc_ip_base
+#define NFC_REG_BASE nfc_axi_base
#endif
#define NFC_BUF_SIZE (NFC_REG_BASE + 0xE00)
#define NFC_BUF_ADDR (NFC_REG_BASE + 0xE04)
@@ -517,18 +539,18 @@ do { \
/*!
* Addresses for NFC RAM BUFFER Main area 0
*/
-#define MAIN_AREA0 (u16 *)(nfc_ip_base + 0x000)
-#define MAIN_AREA1 (u16 *)(nfc_ip_base + 0x200)
+#define MAIN_AREA0 (u16 *)(nfc_axi_base + 0x000)
+#define MAIN_AREA1 (u16 *)(nfc_axi_base + 0x200)
/*!
* Addresses for NFC SPARE BUFFER Spare area 0
*/
#ifdef CONFIG_ARCH_MXC_HAS_NFC_V2_1
-#define SPARE_AREA0 (u16 *)(nfc_ip_base + 0x1000)
+#define SPARE_AREA0 (u16 *)(nfc_axi_base + 0x1000)
#define SPARE_LEN 64
#define SPARE_COUNT 8
#else
-#define SPARE_AREA0 (u16 *)(nfc_ip_base + 0x800)
+#define SPARE_AREA0 (u16 *)(nfc_axi_base + 0x800)
#define SPARE_LEN 16
#define SPARE_COUNT 4
#endif
@@ -539,8 +561,6 @@ do { \
#define SPAS_SHIFT (0)
#define REG_NFC_SPAS NFC_SPAS
#define SPAS_MASK (0xFF00)
-#define IS_4BIT_ECC \
- ((raw_read(REG_NFC_ECC_MODE) & NFC_ECC_MODE_4) >> 0)
#define NFC_SET_SPAS(v) \
raw_write(((raw_read(REG_NFC_SPAS) & SPAS_MASK) | ((v<<SPAS_SHIFT))), \
@@ -578,7 +598,6 @@ do { \
} \
} while (0)
#else
-#define IS_4BIT_ECC (1)
#define NFC_SET_SPAS(v)
#define NFC_SET_ECC_MODE(v)
#define GET_ECC_STATUS() raw_read(REG_NFC_ECC_STATUS_RESULT);
diff --git a/drivers/mtd/nand/nand_device_info.c b/drivers/mtd/nand/nand_device_info.c
index ecd5b21189cc..1ab1d1d21811 100644
--- a/drivers/mtd/nand/nand_device_info.c
+++ b/drivers/mtd/nand/nand_device_info.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -1284,9 +1284,9 @@ static struct nand_device_info nand_device_info_table_type_9[] __initdata =
.data_hold_in_ns = 10,
.address_setup_in_ns = 25,
.gpmi_sample_delay_in_ns = 6,
- .tREA_in_ns = -1,
- .tRLOH_in_ns = -1,
- .tRHOH_in_ns = -1,
+ .tREA_in_ns = 20,
+ .tRLOH_in_ns = 5,
+ .tRHOH_in_ns = 15,
"K9LBG08U0D",
},
{
diff --git a/drivers/mxc/Kconfig b/drivers/mxc/Kconfig
index 6e67087d2efa..b26c1dc11ad6 100644
--- a/drivers/mxc/Kconfig
+++ b/drivers/mxc/Kconfig
@@ -33,6 +33,7 @@ source "drivers/mxc/bt/Kconfig"
source "drivers/mxc/gps_ioctrl/Kconfig"
source "drivers/mxc/mlb/Kconfig"
source "drivers/mxc/adc/Kconfig"
+source "drivers/mxc/amd-gpu/Kconfig"
endmenu
diff --git a/drivers/mxc/Makefile b/drivers/mxc/Makefile
index 6416bc429888..5193fa50eb9f 100644
--- a/drivers/mxc/Makefile
+++ b/drivers/mxc/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_MXC_BLUETOOTH) += bt/
obj-$(CONFIG_GPS_IOCTRL) += gps_ioctrl/
obj-$(CONFIG_MXC_MLB) += mlb/
obj-$(CONFIG_IMX_ADC) += adc/
+obj-$(CONFIG_MXC_AMD_GPU) += amd-gpu/
diff --git a/drivers/mxc/ipu/ipu_common.c b/drivers/mxc/ipu/ipu_common.c
index 43ba100b5c5d..a1dc566e7f8f 100644
--- a/drivers/mxc/ipu/ipu_common.c
+++ b/drivers/mxc/ipu/ipu_common.c
@@ -707,6 +707,38 @@ int32_t ipu_select_buffer(ipu_channel_t channel, ipu_buffer_t type,
}
/*!
+ * This function check buffer ready for a logical channel.
+ *
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param type Input parameter which buffer to clear.
+ *
+ * @param bufNum Input parameter for which buffer number clear
+ * ready state.
+ *
+ */
+int32_t ipu_check_buffer_busy(ipu_channel_t channel, ipu_buffer_t type,
+ uint32_t bufNum)
+{
+ uint32_t dma_chan = channel_2_dma(channel, type);
+ uint32_t reg;
+
+ if (dma_chan == IDMA_CHAN_INVALID)
+ return -EINVAL;
+
+ if (bufNum == 0)
+ reg = __raw_readl(IPU_CHA_BUF0_RDY);
+ else
+ reg = __raw_readl(IPU_CHA_BUF1_RDY);
+
+ if (reg & (1UL << dma_chan))
+ return 1;
+ else
+ return 0;
+}
+EXPORT_SYMBOL(ipu_check_buffer_busy);
+
+/*!
* This function links 2 channels together for automatic frame
* synchronization. The output of the source channel is linked to the input of
* the destination channel.
diff --git a/drivers/mxc/ipu/ipu_csi.c b/drivers/mxc/ipu/ipu_csi.c
index 10708cf3ba54..58d58c10af51 100644
--- a/drivers/mxc/ipu/ipu_csi.c
+++ b/drivers/mxc/ipu/ipu_csi.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -90,10 +90,13 @@ ipu_csi_init_interface(uint16_t width, uint16_t height, uint32_t pixel_fmt,
__raw_writel(height << 16 | 0x22, CSI_FLASH_STROBE_2);
/* Set CCIR registers */
- if ((sig.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) ||
- (sig.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED)) {
+ if (sig.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) {
__raw_writel(0x40030, CSI_CCIR_CODE_1);
__raw_writel(0xFF0000, CSI_CCIR_CODE_3);
+ } else if (sig.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED) {
+ __raw_writel(0xD07DF, CSI_CCIR_CODE_1);
+ __raw_writel(0x40596, CSI_CCIR_CODE_2);
+ __raw_writel(0xFF0000, CSI_CCIR_CODE_3);
}
dev_dbg(g_ipu_dev, "CSI_SENS_CONF = 0x%08X\n",
diff --git a/drivers/mxc/ipu/ipu_device.c b/drivers/mxc/ipu/ipu_device.c
index 5fd1c51ec9b1..713ba2005ae9 100644
--- a/drivers/mxc/ipu/ipu_device.c
+++ b/drivers/mxc/ipu/ipu_device.c
@@ -169,6 +169,7 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file,
sizeof(ipu_channel_buf_parm))) {
return -EFAULT;
}
+
ret =
ipu_init_channel_buffer(parm.channel, parm.type,
parm.pixel_fmt,
diff --git a/drivers/mxc/ipu/ipu_ic.c b/drivers/mxc/ipu/ipu_ic.c
index cdf823a2760b..9fe087590368 100644
--- a/drivers/mxc/ipu/ipu_ic.c
+++ b/drivers/mxc/ipu/ipu_ic.c
@@ -71,8 +71,7 @@ void _ipu_ic_enable_task(ipu_channel_t channel)
case MEM_ROT_PP_MEM:
ic_conf |= IC_CONF_PP_ROT_EN;
break;
- case CSI_MEM:
- // ???
+ case CSI_MEM1:
ic_conf |= IC_CONF_RWS_EN | IC_CONF_PRPENC_EN;
break;
default:
@@ -110,8 +109,7 @@ void _ipu_ic_disable_task(ipu_channel_t channel)
case MEM_ROT_PP_MEM:
ic_conf &= ~IC_CONF_PP_ROT_EN;
break;
- case CSI_MEM:
- // ???
+ case CSI_MEM1:
ic_conf &= ~(IC_CONF_RWS_EN | IC_CONF_PRPENC_EN);
break;
default:
diff --git a/drivers/mxc/ipu/pf/mxc_pf.c b/drivers/mxc/ipu/pf/mxc_pf.c
index 744152415e3a..8abffb4d8d44 100644
--- a/drivers/mxc/ipu/pf/mxc_pf.c
+++ b/drivers/mxc/ipu/pf/mxc_pf.c
@@ -108,6 +108,7 @@ static int mxc_pf_init(pf_init_params * pf_init)
memset(&params, 0, sizeof(params));
params.mem_pf_mem.operation = pf_data.mode;
+
err = ipu_init_channel(MEM_PF_Y_MEM, &params);
if (err < 0) {
printk(KERN_ERR "mxc_pf: error initializing channel\n");
diff --git a/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c
index 6a29c90fe095..5d5e0b9155a0 100644
--- a/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c
+++ b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c
@@ -260,7 +260,7 @@ int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
input_frame_width >> 1;
left->output_width = right->output_width = right->output_column =
output_frame_width >> 1;
- left->input_column = right->input_column = 0;
+ left->input_column = 0;
div = _do_div(((((u64)irr_steps) << 32) *
(right->input_width - 1)), (right->output_width - 1));
left->irr = right->irr = truncate(0, div, 1);
diff --git a/drivers/mxc/ipu3/ipu_capture.c b/drivers/mxc/ipu3/ipu_capture.c
index 5d084ab37b0b..b9967135eac1 100644
--- a/drivers/mxc/ipu3/ipu_capture.c
+++ b/drivers/mxc/ipu3/ipu_capture.c
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/ipu.h>
#include <linux/clk.h>
+#include <mach/mxc_dvfs.h>
#include "ipu_prv.h"
#include "ipu_regs.h"
@@ -93,6 +94,12 @@ ipu_csi_init_interface(uint16_t width, uint16_t height, uint32_t pixel_fmt,
cfg_param.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
cfg_param.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
spin_lock_irqsave(&ipu_lock, lock_flags);
__raw_writel(data, CSI_SENS_CONF(csi));
@@ -101,11 +108,18 @@ ipu_csi_init_interface(uint16_t width, uint16_t height, uint32_t pixel_fmt,
__raw_writel((width - 1) | (height - 1) << 16, CSI_SENS_FRM_SIZE(csi));
/* Set CCIR registers */
- if ((cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) ||
- (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED)) {
- _ipu_csi_ccir_err_detection_enable(csi);
+ if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) {
__raw_writel(0x40030, CSI_CCIR_CODE_1(csi));
__raw_writel(0xFF0000, CSI_CCIR_CODE_3(csi));
+ } else if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED) {
+ _ipu_csi_ccir_err_detection_enable(csi);
+ /* Field0BlankEnd = 0x7, Field0BlankStart = 0x3,
+ Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1 */
+ __raw_writel(0xD07DF, CSI_CCIR_CODE_1(csi));
+ /* Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
+ Field1ActiveEnd = 0x4, Field1ActiveStart = 0 */
+ __raw_writel(0x40596, CSI_CCIR_CODE_2(csi));
+ __raw_writel(0xFF0000, CSI_CCIR_CODE_3(csi));
} else if ((cfg_param.clk_mode ==
IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR) ||
(cfg_param.clk_mode ==
@@ -171,34 +185,13 @@ int _ipu_csi_mclk_set(uint32_t pixel_clk, uint32_t csi)
*/
int ipu_csi_enable_mclk(int csi, bool flag, bool wait)
{
- struct clk *clk;
if (flag) {
- if (cpu_is_mx53()) {
- if (csi == 0) {
- clk = clk_get(NULL, "ssi_ext1_clk");
- clk_enable(clk);
- clk_put(clk);
- } else {
- pr_err("invalid csi num %d\n", csi);
- return -EINVAL;
- }
- } else
- clk_enable(g_csi_clk[csi]);
+ clk_enable(g_csi_clk[csi]);
if (wait == true)
msleep(10);
} else {
- if (cpu_is_mx53()) {
- if (csi == 0) {
- clk = clk_get(NULL, "ssi_ext1_clk");
- clk_disable(clk);
- clk_put(clk);
- } else {
- pr_err("invalid csi num %d\n", csi);
- return -EINVAL;
- }
- } else
- clk_disable(g_csi_clk[csi]);
+ clk_disable(g_csi_clk[csi]);
}
return 0;
@@ -217,6 +210,12 @@ void ipu_csi_get_window_size(uint32_t *width, uint32_t *height, uint32_t csi)
uint32_t reg;
unsigned long lock_flags;
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
spin_lock_irqsave(&ipu_lock, lock_flags);
reg = __raw_readl(CSI_ACT_FRM_SIZE(csi));
@@ -238,6 +237,12 @@ void ipu_csi_set_window_size(uint32_t width, uint32_t height, uint32_t csi)
{
unsigned long lock_flags;
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
spin_lock_irqsave(&ipu_lock, lock_flags);
__raw_writel((width - 1) | (height - 1) << 16, CSI_ACT_FRM_SIZE(csi));
@@ -258,6 +263,12 @@ void ipu_csi_set_window_pos(uint32_t left, uint32_t top, uint32_t csi)
uint32_t temp;
unsigned long lock_flags;
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
spin_lock_irqsave(&ipu_lock, lock_flags);
temp = __raw_readl(CSI_OUT_FRM_CTRL(csi));
@@ -280,6 +291,12 @@ void _ipu_csi_horizontal_downsize_enable(uint32_t csi)
uint32_t temp;
unsigned long lock_flags;
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
spin_lock_irqsave(&ipu_lock, lock_flags);
temp = __raw_readl(CSI_OUT_FRM_CTRL(csi));
@@ -300,6 +317,12 @@ void _ipu_csi_horizontal_downsize_disable(uint32_t csi)
uint32_t temp;
unsigned long lock_flags;
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
spin_lock_irqsave(&ipu_lock, lock_flags);
temp = __raw_readl(CSI_OUT_FRM_CTRL(csi));
@@ -320,6 +343,12 @@ void _ipu_csi_vertical_downsize_enable(uint32_t csi)
uint32_t temp;
unsigned long lock_flags;
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
spin_lock_irqsave(&ipu_lock, lock_flags);
temp = __raw_readl(CSI_OUT_FRM_CTRL(csi));
@@ -340,6 +369,12 @@ void _ipu_csi_vertical_downsize_disable(uint32_t csi)
uint32_t temp;
unsigned long lock_flags;
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
spin_lock_irqsave(&ipu_lock, lock_flags);
temp = __raw_readl(CSI_OUT_FRM_CTRL(csi));
@@ -366,6 +401,12 @@ void ipu_csi_set_test_generator(bool active, uint32_t r_value,
uint32_t temp;
unsigned long lock_flags;
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
spin_lock_irqsave(&ipu_lock, lock_flags);
temp = __raw_readl(CSI_TST_CTRL(csi));
@@ -401,6 +442,12 @@ void _ipu_csi_ccir_err_detection_enable(uint32_t csi)
{
uint32_t temp;
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
temp = __raw_readl(CSI_CCIR_CODE_1(csi));
temp |= CSI_CCIR_ERR_DET_EN;
__raw_writel(temp, CSI_CCIR_CODE_1(csi));
@@ -417,6 +464,12 @@ void _ipu_csi_ccir_err_detection_disable(uint32_t csi)
{
uint32_t temp;
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
temp = __raw_readl(CSI_CCIR_CODE_1(csi));
temp &= ~CSI_CCIR_ERR_DET_EN;
__raw_writel(temp, CSI_CCIR_CODE_1(csi));
@@ -442,6 +495,12 @@ int _ipu_csi_set_mipi_di(uint32_t num, uint32_t di_val, uint32_t csi)
goto err;
}
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
spin_lock_irqsave(&ipu_lock, lock_flags);
temp = __raw_readl(CSI_MIPI_DI(csi));
@@ -499,6 +558,12 @@ int _ipu_csi_set_skip_isp(uint32_t skip, uint32_t max_ratio, uint32_t csi)
goto err;
}
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
spin_lock_irqsave(&ipu_lock, lock_flags);
temp = __raw_readl(CSI_SKIP(csi));
@@ -536,6 +601,12 @@ int _ipu_csi_set_skip_smfc(uint32_t skip, uint32_t max_ratio,
goto err;
}
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
spin_lock_irqsave(&ipu_lock, lock_flags);
temp = __raw_readl(CSI_SKIP(csi));
@@ -585,7 +656,6 @@ void _ipu_smfc_init(ipu_channel_t channel, uint32_t mipi_id, uint32_t csi)
default:
return;
}
-
__raw_writel(temp, SMFC_MAP);
}
@@ -604,6 +674,12 @@ void _ipu_smfc_set_wmc(ipu_channel_t channel, bool set, uint32_t level)
uint32_t temp;
unsigned long lock_flags;
+ if (g_ipu_clk_enabled == false) {
+ stop_dvfs_per();
+ g_ipu_clk_enabled = true;
+ clk_enable(g_ipu_clk);
+ }
+
spin_lock_irqsave(&ipu_lock, lock_flags);
temp = __raw_readl(SMFC_WMC);
diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c
index 68be542e8370..b1b8a8b39ae1 100644
--- a/drivers/mxc/ipu3/ipu_common.c
+++ b/drivers/mxc/ipu3/ipu_common.c
@@ -52,8 +52,8 @@ unsigned char g_dc_di_assignment[10];
ipu_channel_t g_ipu_csi_channel[2];
int g_ipu_irq[2];
int g_ipu_hw_rev;
-bool g_sec_chan_en[22];
-bool g_thrd_chan_en[21];
+bool g_sec_chan_en[24];
+bool g_thrd_chan_en[24];
uint32_t g_channel_init_mask;
uint32_t g_channel_enable_mask;
DEFINE_SPINLOCK(ipu_lock);
@@ -354,8 +354,8 @@ static int ipu_probe(struct platform_device *pdev)
g_di_clk[0] = plat_data->di_clk[0];
g_di_clk[1] = plat_data->di_clk[1];
- g_csi_clk[0] = clk_get(&pdev->dev, "csi_mclk1");
- g_csi_clk[1] = clk_get(&pdev->dev, "csi_mclk2");
+ g_csi_clk[0] = plat_data->csi_clk[0];
+ g_csi_clk[1] = plat_data->csi_clk[1];
__raw_writel(0x807FFFFF, IPU_MEM_RST);
while (__raw_readl(IPU_MEM_RST) & 0x80000000) ;
@@ -372,7 +372,7 @@ static int ipu_probe(struct platform_device *pdev)
_ipu_dmfc_init(DMFC_NORMAL, 1);
/* Set sync refresh channels and CSI->mem channel as high priority */
- __raw_writel(0x18800001L, IDMAC_CHA_PRI(0));
+ __raw_writel(0x18800003L, IDMAC_CHA_PRI(0));
/* Set MCU_T to divide MCU access window into 2 */
__raw_writel(0x00400000L | (IPU_MCU_T_DEFAULT << 18), IPU_DISP_GEN);
@@ -415,7 +415,10 @@ int ipu_remove(struct platform_device *pdev)
void ipu_dump_registers(void)
{
+ printk(KERN_DEBUG "--------------------------------------------\n");
printk(KERN_DEBUG "IPU_CONF = \t0x%08X\n", __raw_readl(IPU_CONF));
+ printk(KERN_DEBUG "SMFC_MAP = \t0x%08X\n", __raw_readl(SMFC_MAP));
+ printk(KERN_DEBUG "SMFC_WMC = \t0x%08X\n", __raw_readl(SMFC_WMC));
printk(KERN_DEBUG "IDMAC_CONF = \t0x%08X\n", __raw_readl(IDMAC_CONF));
printk(KERN_DEBUG "IDMAC_CHA_EN1 = \t0x%08X\n",
__raw_readl(IDMAC_CHA_EN(0)));
@@ -451,6 +454,25 @@ void ipu_dump_registers(void)
__raw_readl(IPU_FS_PROC_FLOW3));
printk(KERN_DEBUG "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
__raw_readl(IPU_FS_DISP_FLOW1));
+
+ printk(KERN_DEBUG "IPU_INT_CTRL_1 = \t0x%08X\n", __raw_readl(IPU_INT_CTRL (1)));
+ printk(KERN_DEBUG "IPU_INT_STAT_1 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (1)));
+ printk(KERN_DEBUG "IPU_INT_STAT_2 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (2)));
+ printk(KERN_DEBUG "IPU_INT_STAT_3 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (3)));
+ printk(KERN_DEBUG "IPU_INT_STAT_4 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (4)));
+ printk(KERN_DEBUG "IPU_INT_STAT_5 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (5)));
+ printk(KERN_DEBUG "IPU_INT_STAT_6 = \t0x%08X\n", __raw_readl(IPU_INT_STAT (6)));
+
+ printk(KERN_DEBUG "CSI0_SENS_CONF = \t0x%08X\n", __raw_readl(CSI_SENS_CONF (0)));
+ printk(KERN_DEBUG "CSI0_SENS_FRM_SIZE = \t0x%08X\n", __raw_readl(CSI_SENS_FRM_SIZE(0)));
+ printk(KERN_DEBUG "CSI0_ACT_FRM_SIZE = \t0x%08X\n", __raw_readl(CSI_ACT_FRM_SIZE(0)));
+ printk(KERN_DEBUG "CSI0_SKIP = \t0x%08X\n", __raw_readl(CSI_SKIP(0)));
+
+ printk(KERN_DEBUG "CSI1_SENS_CONF = \t0x%08X\n", __raw_readl(CSI_SENS_CONF (1)));
+ printk(KERN_DEBUG "CSI1_SENS_FRM_SIZE = \t0x%08X\n", __raw_readl(CSI_SENS_FRM_SIZE(1)));
+ printk(KERN_DEBUG "CSI1_ACT_FRM_SIZE = \t0x%08X\n", __raw_readl(CSI_ACT_FRM_SIZE(1)));
+ printk(KERN_DEBUG "CSI1_SKIP = \t0x%08X\n", __raw_readl(CSI_SKIP(1)));
+ printk(KERN_DEBUG "--------------------------------------------\n");
}
/*!
@@ -660,7 +682,8 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
g_dc_di_assignment[1] = params->mem_dc_sync.di;
_ipu_dc_init(1, params->mem_dc_sync.di,
- params->mem_dc_sync.interlaced);
+ params->mem_dc_sync.interlaced,
+ params->mem_dc_sync.out_pixel_fmt);
ipu_di_use_count[params->mem_dc_sync.di]++;
ipu_dc_use_count++;
ipu_dmfc_use_count++;
@@ -678,7 +701,8 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
_ipu_dp_init(channel, params->mem_dp_bg_sync.in_pixel_fmt,
params->mem_dp_bg_sync.out_pixel_fmt);
_ipu_dc_init(5, params->mem_dp_bg_sync.di,
- params->mem_dp_bg_sync.interlaced);
+ params->mem_dp_bg_sync.interlaced,
+ params->mem_dp_bg_sync.out_pixel_fmt);
ipu_di_use_count[params->mem_dp_bg_sync.di]++;
ipu_dc_use_count++;
ipu_dp_use_count++;
@@ -702,7 +726,7 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
}
g_dc_di_assignment[8] = params->direct_async.di;
- _ipu_dc_init(8, params->direct_async.di, false);
+ _ipu_dc_init(8, params->direct_async.di, false, IPU_PIX_FMT_GENERIC);
ipu_di_use_count[params->direct_async.di]++;
ipu_dc_use_count++;
break;
@@ -713,7 +737,7 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
}
g_dc_di_assignment[9] = params->direct_async.di;
- _ipu_dc_init(9, params->direct_async.di, false);
+ _ipu_dc_init(9, params->direct_async.di, false, IPU_PIX_FMT_GENERIC);
ipu_di_use_count[params->direct_async.di]++;
ipu_dc_use_count++;
break;
@@ -724,31 +748,8 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
/* Enable IPU sub module */
g_channel_init_mask |= 1L << IPU_CHAN_ID(channel);
- if (ipu_ic_use_count == 1)
- ipu_conf |= IPU_CONF_IC_EN;
- if (ipu_vdi_use_count == 1) {
- ipu_conf |= IPU_CONF_VDI_EN;
- ipu_conf |= IPU_CONF_IC_INPUT;
- }
- if (ipu_rot_use_count == 1)
- ipu_conf |= IPU_CONF_ROT_EN;
- if (ipu_dc_use_count == 1)
- ipu_conf |= IPU_CONF_DC_EN;
- if (ipu_dp_use_count == 1)
- ipu_conf |= IPU_CONF_DP_EN;
- if (ipu_dmfc_use_count == 1)
- ipu_conf |= IPU_CONF_DMFC_EN;
- if (ipu_di_use_count[0] == 1) {
- ipu_conf |= IPU_CONF_DI0_EN;
- }
- if (ipu_di_use_count[1] == 1) {
- ipu_conf |= IPU_CONF_DI1_EN;
- }
- if (ipu_smfc_use_count == 1)
- ipu_conf |= IPU_CONF_SMFC_EN;
__raw_writel(ipu_conf, IPU_CONF);
-
err:
spin_unlock_irqrestore(&ipu_lock, lock_flags);
return ret;
@@ -775,8 +776,8 @@ void ipu_uninit_channel(ipu_channel_t channel)
/* Make sure channel is disabled */
/* Get input and output dma channels */
- in_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
- out_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+ in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+ out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
if (idma_is_set(IDMAC_CHA_EN, in_dma) ||
idma_is_set(IDMAC_CHA_EN, out_dma)) {
@@ -796,8 +797,10 @@ void ipu_uninit_channel(ipu_channel_t channel)
reg = __raw_readl(IPU_CHA_DB_MODE_SEL(out_dma));
__raw_writel(reg & ~idma_mask(out_dma), IPU_CHA_DB_MODE_SEL(out_dma));
- g_sec_chan_en[IPU_CHAN_ID(channel)] = false;
- g_thrd_chan_en[IPU_CHAN_ID(channel)] = false;
+ if (_ipu_is_ic_chan(in_dma) || _ipu_is_dp_graphic_chan(in_dma)) {
+ g_sec_chan_en[IPU_CHAN_ID(channel)] = false;
+ g_thrd_chan_en[IPU_CHAN_ID(channel)] = false;
+ }
switch (channel) {
case CSI_MEM0:
@@ -849,6 +852,9 @@ void ipu_uninit_channel(ipu_channel_t channel)
reg = __raw_readl(IPU_FS_PROC_FLOW1);
__raw_writel(reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
break;
+ case MEM_VDI_PRP_VF_MEM_P:
+ case MEM_VDI_PRP_VF_MEM_N:
+ break;
case MEM_ROT_VF_MEM:
ipu_rot_use_count--;
ipu_ic_use_count--;
@@ -913,6 +919,7 @@ void ipu_uninit_channel(ipu_channel_t channel)
if (ipu_ic_use_count == 0)
ipu_conf &= ~IPU_CONF_IC_EN;
if (ipu_vdi_use_count == 0) {
+ ipu_conf &= ~IPU_CONF_ISP_EN;
ipu_conf &= ~IPU_CONF_VDI_EN;
ipu_conf &= ~IPU_CONF_IC_INPUT;
}
@@ -1239,8 +1246,6 @@ int32_t ipu_select_buffer(ipu_channel_t channel, ipu_buffer_t type,
__raw_writel(idma_mask(dma_chan) | reg,
IPU_CHA_BUF1_RDY(dma_chan));
}
- if (channel == MEM_VDI_PRP_VF_MEM)
- _ipu_vdi_toggle_top_field_man();
return 0;
}
EXPORT_SYMBOL(ipu_select_buffer);
@@ -1269,10 +1274,9 @@ int32_t ipu_select_multi_vdi_buffer(uint32_t bufNum)
__raw_writel(mask_bit | reg, IPU_CHA_BUF0_RDY(dma_chan));
} else {
/*Mark buffer 1 as ready. */
- reg = __raw_readl(IPU_CHA_BUF0_RDY(dma_chan));
+ reg = __raw_readl(IPU_CHA_BUF1_RDY(dma_chan));
__raw_writel(mask_bit | reg, IPU_CHA_BUF1_RDY(dma_chan));
}
- _ipu_vdi_toggle_top_field_man();
return 0;
}
EXPORT_SYMBOL(ipu_select_multi_vdi_buffer);
@@ -1282,7 +1286,7 @@ static int proc_dest_sel[] =
{ 0, 1, 1, 3, 5, 5, 4, 7, 8, 9, 10, 11, 12, 14, 15, 16,
0, 1, 1, 5, 5, 5, 5, 5, 7, 8, 9, 10, 11, 12, 14, 31 };
static int proc_src_sel[] = { 0, 6, 7, 6, 7, 8, 5, NA, NA, NA,
- NA, NA, NA, NA, NA, 1, 2, 3, 4, 7, 8, NA, NA, NA };
+ NA, NA, NA, NA, NA, 1, 2, 3, 4, 7, 8, NA, 8, NA };
static int disp_src_sel[] = { 0, 6, 7, 8, 3, 4, 5, NA, NA, NA,
NA, NA, NA, NA, NA, 1, NA, 2, NA, 3, 4, 4, 4, 4 };
@@ -1659,6 +1663,7 @@ int32_t ipu_enable_channel(ipu_channel_t channel)
{
uint32_t reg;
unsigned long lock_flags;
+ uint32_t ipu_conf;
uint32_t in_dma;
uint32_t out_dma;
uint32_t sec_dma;
@@ -1675,6 +1680,32 @@ int32_t ipu_enable_channel(ipu_channel_t channel)
spin_lock_irqsave(&ipu_lock, lock_flags);
+ ipu_conf = __raw_readl(IPU_CONF);
+ if (ipu_di_use_count[0] > 0) {
+ ipu_conf |= IPU_CONF_DI0_EN;
+ }
+ if (ipu_di_use_count[1] > 0) {
+ ipu_conf |= IPU_CONF_DI1_EN;
+ }
+ if (ipu_dp_use_count > 0)
+ ipu_conf |= IPU_CONF_DP_EN;
+ if (ipu_dc_use_count > 0)
+ ipu_conf |= IPU_CONF_DC_EN;
+ if (ipu_dmfc_use_count > 0)
+ ipu_conf |= IPU_CONF_DMFC_EN;
+ if (ipu_ic_use_count > 0)
+ ipu_conf |= IPU_CONF_IC_EN;
+ if (ipu_vdi_use_count > 0) {
+ ipu_conf |= IPU_CONF_ISP_EN;
+ ipu_conf |= IPU_CONF_VDI_EN;
+ ipu_conf |= IPU_CONF_IC_INPUT;
+ }
+ if (ipu_rot_use_count > 0)
+ ipu_conf |= IPU_CONF_ROT_EN;
+ if (ipu_smfc_use_count > 0)
+ ipu_conf |= IPU_CONF_SMFC_EN;
+ __raw_writel(ipu_conf, IPU_CONF);
+
if (idma_is_valid(in_dma)) {
reg = __raw_readl(IDMAC_CHA_EN(in_dma));
__raw_writel(reg | idma_mask(in_dma), IDMAC_CHA_EN(in_dma));
@@ -1710,8 +1741,11 @@ int32_t ipu_enable_channel(ipu_channel_t channel)
}
if ((channel == MEM_DC_SYNC) || (channel == MEM_BG_SYNC) ||
- (channel == MEM_FG_SYNC))
+ (channel == MEM_FG_SYNC)) {
+ reg = __raw_readl(IDMAC_WM_EN(in_dma));
+ __raw_writel(reg | idma_mask(in_dma), IDMAC_WM_EN(in_dma));
_ipu_dp_dc_enable(channel);
+ }
if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) ||
_ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma))
@@ -1726,6 +1760,38 @@ int32_t ipu_enable_channel(ipu_channel_t channel)
EXPORT_SYMBOL(ipu_enable_channel);
/*!
+ * This function check buffer ready for a logical channel.
+ *
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param type Input parameter which buffer to clear.
+ *
+ * @param bufNum Input parameter for which buffer number clear
+ * ready state.
+ *
+ */
+int32_t ipu_check_buffer_busy(ipu_channel_t channel, ipu_buffer_t type,
+ uint32_t bufNum)
+{
+ uint32_t dma_chan = channel_2_dma(channel, type);
+ uint32_t reg;
+
+ if (dma_chan == IDMA_CHAN_INVALID)
+ return -EINVAL;
+
+ if (bufNum == 0)
+ reg = __raw_readl(IPU_CHA_BUF0_RDY(dma_chan));
+ else
+ reg = __raw_readl(IPU_CHA_BUF1_RDY(dma_chan));
+
+ if (reg & idma_mask(dma_chan))
+ return 1;
+ else
+ return 0;
+}
+EXPORT_SYMBOL(ipu_check_buffer_busy);
+
+/*!
* This function clear buffer ready for a logical channel.
*
* @param channel Input parameter for the logical channel ID.
@@ -1817,7 +1883,30 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop)
if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) ||
(channel == MEM_DC_SYNC)) {
+ if (channel == MEM_FG_SYNC)
+ ipu_disp_set_window_pos(channel, 0, 0);
+
_ipu_dp_dc_disable(channel, false);
+
+ /*
+ * wait for BG channel EOF then disable FG-IDMAC,
+ * it avoid FG NFB4EOF error.
+ */
+ if (channel == MEM_FG_SYNC) {
+ int timeout = 50;
+
+ __raw_writel(IPUIRQ_2_MASK(IPU_IRQ_BG_SYNC_EOF),
+ IPUIRQ_2_STATREG(IPU_IRQ_BG_SYNC_EOF));
+ while ((__raw_readl(IPUIRQ_2_STATREG(IPU_IRQ_BG_SYNC_EOF)) &
+ IPUIRQ_2_MASK(IPU_IRQ_BG_SYNC_EOF)) == 0) {
+ msleep(10);
+ timeout -= 10;
+ if (timeout <= 0) {
+ dev_err(g_ipu_dev, "warning: wait for bg sync eof timeout\n");
+ break;
+ }
+ }
+ }
} else if (wait_for_stop) {
while (idma_is_set(IDMAC_CHA_BUSY, in_dma) ||
idma_is_set(IDMAC_CHA_BUSY, out_dma) ||
@@ -1861,6 +1950,12 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop)
spin_lock_irqsave(&ipu_lock, lock_flags);
+ if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) ||
+ (channel == MEM_DC_SYNC)) {
+ reg = __raw_readl(IDMAC_WM_EN(in_dma));
+ __raw_writel(reg & ~idma_mask(in_dma), IDMAC_WM_EN(in_dma));
+ }
+
/* Disable IC task */
if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) ||
_ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma))
@@ -1897,8 +1992,6 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop)
g_channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel));
- spin_unlock_irqrestore(&ipu_lock, lock_flags);
-
/* Set channel buffers NOT to be ready */
if (idma_is_valid(in_dma)) {
ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 0);
@@ -1917,6 +2010,8 @@ int32_t ipu_disable_channel(ipu_channel_t channel, bool wait_for_stop)
ipu_clear_buffer_ready(channel, IPU_ALPHA_IN_BUFFER, 1);
}
+ spin_unlock_irqrestore(&ipu_lock, lock_flags);
+
return 0;
}
EXPORT_SYMBOL(ipu_disable_channel);
@@ -2029,7 +2124,6 @@ static irqreturn_t ipu_irq_handler(int irq, void *desc)
dev_id);
}
}
-
return result;
}
diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c
index 27455fe26ab6..bf71ea833f58 100644
--- a/drivers/mxc/ipu3/ipu_device.c
+++ b/drivers/mxc/ipu3/ipu_device.c
@@ -124,7 +124,6 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file,
(&parm, (ipu_channel_buf_parm *) arg,
sizeof(ipu_channel_buf_parm)))
return -EFAULT;
-
ret =
ipu_init_channel_buffer(
parm.channel, parm.type,
@@ -183,6 +182,17 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file,
}
break;
+ case IPU_SELECT_MULTI_VDI_BUFFER:
+ {
+ uint32_t parm;
+ if (copy_from_user
+ (&parm, (uint32_t *) arg,
+ sizeof(uint32_t)))
+ return -EFAULT;
+
+ ret = ipu_select_multi_vdi_buffer(parm);
+ }
+ break;
case IPU_LINK_CHANNELS:
{
ipu_channel_link link;
@@ -225,7 +235,6 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file,
(&info, (ipu_channel_info *) arg,
sizeof(ipu_channel_info)))
return -EFAULT;
-
ret = ipu_disable_channel(info.channel,
info.stop);
}
@@ -435,7 +444,7 @@ static int mxc_ipu_ioctl(struct inode *inode, struct file *file,
static int mxc_ipu_mmap(struct file *file, struct vm_area_struct *vma)
{
-// vma->vm_page_prot = pgprot_writethru(vma->vm_page_prot);
+ vma->vm_page_prot = pgprot_writethru(vma->vm_page_prot);
if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start,
@@ -452,12 +461,20 @@ static int mxc_ipu_release(struct inode *inode, struct file *file)
return 0;
}
+int mxc_ipu_fsync(struct file *filp, struct dentry *dentry, int datasync)
+{
+ flush_cache_all();
+ outer_flush_all();
+ return 0;
+}
+
static struct file_operations mxc_ipu_fops = {
.owner = THIS_MODULE,
.open = mxc_ipu_open,
.mmap = mxc_ipu_mmap,
.release = mxc_ipu_release,
- .ioctl = mxc_ipu_ioctl
+ .ioctl = mxc_ipu_ioctl,
+ .fsync = mxc_ipu_fsync
};
int register_ipu_device()
diff --git a/drivers/mxc/ipu3/ipu_disp.c b/drivers/mxc/ipu3/ipu_disp.c
index 00c5008d149f..14dde404990b 100644
--- a/drivers/mxc/ipu3/ipu_disp.c
+++ b/drivers/mxc/ipu3/ipu_disp.c
@@ -147,6 +147,37 @@ static int __init dmfc_setup(char *options)
}
__setup("dmfc=", dmfc_setup);
+static bool _ipu_update_dmfc_used_size(int dma_chan, int width, int dmfc_size)
+{
+ u32 fifo_size_5f = 1;
+ u32 dmfc_dp_chan = __raw_readl(DMFC_DP_CHAN);
+
+ if ((width > 352) && (dmfc_size == (256 * 4)))
+ fifo_size_5f = 1;
+ else if (width > 176)
+ fifo_size_5f = 2;
+ else if (width > 88)
+ fifo_size_5f = 3;
+ else if (width > 44)
+ fifo_size_5f = 4;
+ else if (width > 22)
+ fifo_size_5f = 5;
+ else if (width > 11)
+ fifo_size_5f = 6;
+ else if (width > 6)
+ fifo_size_5f = 7;
+ else
+ return false;
+
+ if (dma_chan == 27) {
+ dmfc_dp_chan &= ~DMFC_FIFO_SIZE_5F;
+ dmfc_dp_chan |= fifo_size_5f << 11;
+ __raw_writel(dmfc_dp_chan, DMFC_DP_CHAN);
+ }
+
+ return true;
+}
+
void _ipu_dmfc_set_wait4eot(int dma_chan, int width)
{
u32 dmfc_gen1 = __raw_readl(DMFC_GENERAL1);
@@ -169,7 +200,7 @@ void _ipu_dmfc_set_wait4eot(int dma_chan, int width)
else
dmfc_gen1 &= ~(1UL << 22);
} else if (dma_chan == 27) { /*5F*/
- if (dmfc_size_27/width > 2)
+ if (!_ipu_update_dmfc_used_size(dma_chan, width, dmfc_size_27))
dmfc_gen1 |= 1UL << 21;
else
dmfc_gen1 &= ~(1UL << 21);
@@ -245,6 +276,24 @@ static void _ipu_di_sync_config(int di, int wave_gen,
__raw_writel(reg, DI_STP_REP(di, wave_gen));
}
+static void _ipu_dc_map_link(int current_map,
+ int base_map_0, int buf_num_0,
+ int base_map_1, int buf_num_1,
+ int base_map_2, int buf_num_2)
+{
+ int ptr_0 = base_map_0 * 3 + buf_num_0;
+ int ptr_1 = base_map_1 * 3 + buf_num_1;
+ int ptr_2 = base_map_2 * 3 + buf_num_2;
+ int ptr;
+ u32 reg;
+ ptr = (ptr_2 << 10) + (ptr_1 << 5) + ptr_0;
+
+ reg = __raw_readl(DC_MAP_CONF_PTR(current_map));
+ reg &= ~(0x1F << ((16 * (current_map & 0x1))));
+ reg |= ptr << ((16 * (current_map & 0x1)));
+ __raw_writel(reg, DC_MAP_CONF_PTR(current_map));
+}
+
static void _ipu_dc_map_config(int map, int byte_num, int offset, int mask)
{
int ptr = map * 3 + byte_num;
@@ -269,32 +318,63 @@ static void _ipu_dc_map_clear(int map)
}
static void _ipu_dc_write_tmpl(int word, u32 opcode, u32 operand, int map,
- int wave, int glue, int sync)
+ int wave, int glue, int sync, int stop)
{
u32 reg;
- int stop = 1;
-
- reg = sync;
- reg |= (glue << 4);
- reg |= (++wave << 11);
- reg |= (++map << 15);
- reg |= (operand << 20) & 0xFFF00000;
- __raw_writel(reg, ipu_dc_tmpl_reg + word * 2);
-
- reg = (operand >> 12);
- reg |= opcode << 4;
- reg |= (stop << 9);
- __raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1);
+
+ if (opcode == WRG) {
+ reg = sync;
+ reg |= (glue << 4);
+ reg |= (++wave << 11);
+ reg |= ((operand & 0x1FFFF) << 15);
+ __raw_writel(reg, ipu_dc_tmpl_reg + word * 2);
+
+ reg = (operand >> 17);
+ reg |= opcode << 7;
+ reg |= (stop << 9);
+ __raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1);
+ } else {
+ reg = sync;
+ reg |= (glue << 4);
+ reg |= (++wave << 11);
+ reg |= (++map << 15);
+ reg |= (operand << 20) & 0xFFF00000;
+ __raw_writel(reg, ipu_dc_tmpl_reg + word * 2);
+
+ reg = (operand >> 12);
+ reg |= opcode << 4;
+ reg |= (stop << 9);
+ __raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1);
+ }
}
static void _ipu_dc_link_event(int chan, int event, int addr, int priority)
{
u32 reg;
-
- reg = __raw_readl(DC_RL_CH(chan, event));
- reg &= ~(0xFFFF << (16 * (event & 0x1)));
- reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
- __raw_writel(reg, DC_RL_CH(chan, event));
+ u32 address_shift;
+ if (event < DC_EVEN_UGDE0) {
+ reg = __raw_readl(DC_RL_CH(chan, event));
+ reg &= ~(0xFFFF << (16 * (event & 0x1)));
+ reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
+ __raw_writel(reg, DC_RL_CH(chan, event));
+ } else {
+ reg = __raw_readl(DC_UGDE_0((event - DC_EVEN_UGDE0) / 2));
+ if ((event - DC_EVEN_UGDE0) & 0x1) {
+ reg &= ~(0x2FF << 16);
+ reg |= (addr << 16);
+ reg |= priority ? (2 << 24) : 0x0;
+ } else {
+ reg &= ~0xFC00FFFF;
+ if (priority)
+ chan = (chan >> 1) +
+ ((((chan & 0x1) + ((chan & 0x2) >> 1))) | (chan >> 3));
+ else
+ chan = 0x7;
+ address_shift = ((event - DC_EVEN_UGDE0) >> 1) ? 7 : 8;
+ reg |= (addr << address_shift) | (priority << 3) | chan;
+ }
+ __raw_writel(reg, DC_UGDE_0((event - DC_EVEN_UGDE0) / 2));
+ }
}
/* Y = R * 1.200 + G * 2.343 + B * .453 + 0.250;
@@ -503,7 +583,7 @@ void _ipu_dp_uninit(ipu_channel_t channel)
__ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], false);
}
-void _ipu_dc_init(int dc_chan, int di, bool interlaced)
+void _ipu_dc_init(int dc_chan, int di, bool interlaced, uint32_t pixel_fmt)
{
u32 reg = 0;
@@ -517,10 +597,24 @@ void _ipu_dc_init(int dc_chan, int di, bool interlaced)
_ipu_dc_link_event(dc_chan, DC_EVT_NL, 2, 3);
_ipu_dc_link_event(dc_chan, DC_EVT_EOL, 3, 2);
_ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 4, 1);
+ if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+ (pixel_fmt == IPU_PIX_FMT_UYVY) ||
+ (pixel_fmt == IPU_PIX_FMT_YVYU) ||
+ (pixel_fmt == IPU_PIX_FMT_VYUY)) {
+ _ipu_dc_link_event(dc_chan, DC_ODD_UGDE1, 9, 5);
+ _ipu_dc_link_event(dc_chan, DC_EVEN_UGDE1, 8, 5);
+ }
} else {
_ipu_dc_link_event(dc_chan, DC_EVT_NL, 5, 3);
_ipu_dc_link_event(dc_chan, DC_EVT_EOL, 6, 2);
_ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 7, 1);
+ if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+ (pixel_fmt == IPU_PIX_FMT_UYVY) ||
+ (pixel_fmt == IPU_PIX_FMT_YVYU) ||
+ (pixel_fmt == IPU_PIX_FMT_VYUY)) {
+ _ipu_dc_link_event(dc_chan, DC_ODD_UGDE0, 10, 5);
+ _ipu_dc_link_event(dc_chan, DC_EVEN_UGDE0, 11, 5);
+ }
}
}
_ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0);
@@ -562,6 +656,10 @@ void _ipu_dc_uninit(int dc_chan)
_ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0);
_ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0);
_ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0);
+ _ipu_dc_link_event(dc_chan, DC_ODD_UGDE0, 0, 0);
+ _ipu_dc_link_event(dc_chan, DC_EVEN_UGDE0, 0, 0);
+ _ipu_dc_link_event(dc_chan, DC_ODD_UGDE1, 0, 0);
+ _ipu_dc_link_event(dc_chan, DC_EVEN_UGDE1, 0, 0);
} else if ((dc_chan == 8) || (dc_chan == 9)) {
_ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_0, 0, 0);
_ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_1, 0, 0);
@@ -637,6 +735,26 @@ static bool dc_swap;
static irqreturn_t dc_irq_handler(int irq, void *dev_id)
{
struct completion *comp = dev_id;
+ uint32_t reg;
+ uint32_t dc_chan;
+
+ if (irq == IPU_IRQ_DC_FC_1)
+ dc_chan = 1;
+ else
+ dc_chan = 5;
+
+ if (!dc_swap) {
+ reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
+ reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+ __raw_writel(reg, DC_WR_CH_CONF(dc_chan));
+
+ reg = __raw_readl(IPU_DISP_GEN);
+ if (g_dc_di_assignment[dc_chan])
+ reg &= ~DI1_COUNTER_RELEASE;
+ else
+ reg &= ~DI0_COUNTER_RELEASE;
+ __raw_writel(reg, IPU_DISP_GEN);
+ }
complete(comp);
return IRQ_HANDLED;
@@ -689,29 +807,6 @@ void _ipu_dp_dc_disable(ipu_channel_t channel, bool swap)
if (timeout <= 0)
break;
}
-
- timeout = 50;
-
- /*
- * Wait for DC triple buffer to empty,
- * this check is useful for tv overlay.
- */
- if (g_dc_di_assignment[dc_chan] == 0)
- while ((__raw_readl(DC_STAT) & 0x00000002)
- != 0x00000002) {
- msleep(2);
- timeout -= 2;
- if (timeout <= 0)
- break;
- }
- else if (g_dc_di_assignment[dc_chan] == 1)
- while ((__raw_readl(DC_STAT) & 0x00000020)
- != 0x00000020) {
- msleep(2);
- timeout -= 2;
- if (timeout <= 0)
- break;
- }
return;
} else {
return;
@@ -743,39 +838,6 @@ void _ipu_dp_dc_disable(ipu_channel_t channel, bool swap)
__raw_writel(reg, DC_WR_CH_CONF(dc_chan));
spin_unlock_irqrestore(&ipu_lock, lock_flags);
} else {
- timeout = 50;
-
- /* Wait for DC triple buffer to empty */
- if (g_dc_di_assignment[dc_chan] == 0)
- while ((__raw_readl(DC_STAT) & 0x00000002)
- != 0x00000002) {
- msleep(2);
- timeout -= 2;
- if (timeout <= 0)
- break;
- }
- else if (g_dc_di_assignment[dc_chan] == 1)
- while ((__raw_readl(DC_STAT) & 0x00000020)
- != 0x00000020) {
- msleep(2);
- timeout -= 2;
- if (timeout <= 0)
- break;
- }
-
- spin_lock_irqsave(&ipu_lock, lock_flags);
- reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
- reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
- __raw_writel(reg, DC_WR_CH_CONF(dc_chan));
-
- reg = __raw_readl(IPU_DISP_GEN);
- if (g_dc_di_assignment[dc_chan])
- reg &= ~DI1_COUNTER_RELEASE;
- else
- reg &= ~DI0_COUNTER_RELEASE;
- __raw_writel(reg, IPU_DISP_GEN);
-
- spin_unlock_irqrestore(&ipu_lock, lock_flags);
/* Clock is already off because it must be done quickly, but
we need to fix the ref count */
clk_disable(g_pixel_clk[g_dc_di_assignment[dc_chan]]);
@@ -821,6 +883,34 @@ void _ipu_init_dc_mappings(void)
_ipu_dc_map_config(4, 0, 5, 0xFC);
_ipu_dc_map_config(4, 1, 13, 0xFC);
_ipu_dc_map_config(4, 2, 21, 0xFC);
+
+ /* IPU_PIX_FMT_VYUY 16bit width */
+ _ipu_dc_map_clear(5);
+ _ipu_dc_map_config(5, 0, 7, 0xFF);
+ _ipu_dc_map_config(5, 1, 0, 0x0);
+ _ipu_dc_map_config(5, 2, 15, 0xFF);
+ _ipu_dc_map_clear(6);
+ _ipu_dc_map_config(6, 0, 0, 0x0);
+ _ipu_dc_map_config(6, 1, 7, 0xFF);
+ _ipu_dc_map_config(6, 2, 15, 0xFF);
+
+ /* IPU_PIX_FMT_UYUV 16bit width */
+ _ipu_dc_map_clear(7);
+ _ipu_dc_map_link(7, 6, 0, 6, 1, 6, 2);
+ _ipu_dc_map_clear(8);
+ _ipu_dc_map_link(8, 5, 0, 5, 1, 5, 2);
+
+ /* IPU_PIX_FMT_YUYV 16bit width */
+ _ipu_dc_map_clear(9);
+ _ipu_dc_map_link(9, 5, 2, 5, 1, 5, 0);
+ _ipu_dc_map_clear(10);
+ _ipu_dc_map_link(10, 5, 1, 5, 2, 5, 0);
+
+ /* IPU_PIX_FMT_YVYU 16bit width */
+ _ipu_dc_map_clear(11);
+ _ipu_dc_map_link(11, 5, 1, 5, 2, 5, 0);
+ _ipu_dc_map_clear(12);
+ _ipu_dc_map_link(12, 5, 2, 5, 1, 5, 0);
}
int _ipu_pixfmt_to_map(uint32_t fmt)
@@ -837,6 +927,14 @@ int _ipu_pixfmt_to_map(uint32_t fmt)
return 3;
case IPU_PIX_FMT_LVDS666:
return 4;
+ case IPU_PIX_FMT_VYUY:
+ return 6;
+ case IPU_PIX_FMT_UYVY:
+ return 8;
+ case IPU_PIX_FMT_YUYV:
+ return 10;
+ case IPU_PIX_FMT_YVYU:
+ return 12;
}
return -1;
@@ -964,22 +1062,22 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk,
dev_dbg(g_ipu_dev, "pixel clk = %d\n", pixel_clk);
if (sig.ext_clk) {
- /* Set the PLL to be an even multiple of the pixel clock. not round div for tvout*/
- if ((clk_get_usecount(g_pixel_clk[0]) == 0) &&
- (clk_get_usecount(g_pixel_clk[1]) == 0)) {
+ /*
+ * Set the PLL to be an even multiple of the pixel clock.
+ * Not round div for tvout and ldb.
+ * Did not consider both DI come from the same ext clk, if
+ * meet such case, ext clk rate should be set specially.
+ */
+ if (clk_get_usecount(g_pixel_clk[disp]) == 0) {
di_parent = clk_get_parent(g_di_clk[disp]);
- if (strcmp(di_parent->name, "tve_clk") != 0) {
- rounded_pixel_clk =
- clk_round_rate(g_pixel_clk[disp], pixel_clk);
- div = clk_get_rate(di_parent) / rounded_pixel_clk;
- if (div % 2)
- div++;
-
- if (clk_get_rate(di_parent) != div * rounded_pixel_clk)
- clk_set_rate(di_parent, div * rounded_pixel_clk);
- msleep(10);
- clk_set_rate(g_di_clk[disp], 2 * rounded_pixel_clk);
- msleep(10);
+ if (strcmp(di_parent->name, "tve_clk") != 0 &&
+ strcmp(di_parent->name, "ldb_di0_clk") != 0 &&
+ strcmp(di_parent->name, "ldb_di1_clk") != 0) {
+ rounded_pixel_clk = pixel_clk * 2;
+ while (rounded_pixel_clk < 150000000)
+ rounded_pixel_clk += pixel_clk * 2;
+ clk_set_rate(di_parent, rounded_pixel_clk);
+ clk_set_rate(g_di_clk[disp], pixel_clk);
}
}
clk_set_parent(g_pixel_clk[disp], g_di_clk[disp]);
@@ -1019,7 +1117,7 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk,
di_gen = __raw_readl(DI_GENERAL(disp));
if (sig.interlaced) {
- if (cpu_is_mx51_rev(CHIP_REV_2_0)) {
+ if (g_ipu_hw_rev >= 2) {
/* Setup internal HSYNC waveform */
_ipu_di_sync_config(
disp, /* display */
@@ -1259,7 +1357,7 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk,
}
/* Init template microcode */
- _ipu_dc_write_tmpl(0, WROD(0), 0, map, SYNC_WAVE, 0, 8);
+ _ipu_dc_write_tmpl(0, WROD(0), 0, map, SYNC_WAVE, 0, 8, 1);
if (sig.Hsync_pol)
di_gen |= DI_GEN_POLARITY_3;
@@ -1322,13 +1420,31 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk,
/* Init template microcode */
if (disp) {
- _ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5);
- _ipu_dc_write_tmpl(3, WROD(0), 0, map, SYNC_WAVE, 4, 5);
- _ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+ if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+ (pixel_fmt == IPU_PIX_FMT_UYVY) ||
+ (pixel_fmt == IPU_PIX_FMT_YVYU) ||
+ (pixel_fmt == IPU_PIX_FMT_VYUY)) {
+ _ipu_dc_write_tmpl(8, WROD(0), 0, (map - 1), SYNC_WAVE, 0, 5, 1);
+ _ipu_dc_write_tmpl(9, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
+ /* configure user events according to DISP NUM */
+ __raw_writel((width - 1), DC_UGDE_3(disp));
+ }
+ _ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1);
+ _ipu_dc_write_tmpl(3, WRG, 0, map, SYNC_WAVE, 4, 5, 1);
+ _ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
} else {
- _ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5);
- _ipu_dc_write_tmpl(6, WROD(0), 0, map, SYNC_WAVE, 4, 5);
- _ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+ if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+ (pixel_fmt == IPU_PIX_FMT_UYVY) ||
+ (pixel_fmt == IPU_PIX_FMT_YVYU) ||
+ (pixel_fmt == IPU_PIX_FMT_VYUY)) {
+ _ipu_dc_write_tmpl(10, WROD(0), 0, (map - 1), SYNC_WAVE, 0, 5, 1);
+ _ipu_dc_write_tmpl(11, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
+ /* configure user events according to DISP NUM */
+ __raw_writel(width - 1, DC_UGDE_3(disp));
+ }
+ _ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1);
+ _ipu_dc_write_tmpl(6, WRG, 0, map, SYNC_WAVE, 4, 5, 1);
+ _ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
}
if (sig.Hsync_pol)
@@ -1340,6 +1456,19 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk,
/* Set the clock to stop at counter 6. */
di_gen |= 0x6000000;
}
+ /* changinc DISP_CLK polarity: it can be wrong for some applications */
+ if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+ (pixel_fmt == IPU_PIX_FMT_UYVY) ||
+ (pixel_fmt == IPU_PIX_FMT_YVYU) ||
+ (pixel_fmt == IPU_PIX_FMT_VYUY))
+ di_gen |= 0x00020000;
+ else {
+ /* Configure accordingly to the received configuration */
+ if (sig.clk_pol)
+ di_gen |= 0x00020000;
+ else
+ di_gen &= ~0x00020000;
+ }
__raw_writel(di_gen, DI_GENERAL(disp));
@@ -1402,7 +1531,7 @@ int ipu_init_async_panel(int disp, int type, uint32_t cycle_time,
_ipu_di_data_pin_config(disp, ASYNC_SER_WAVE, DI_PIN_SER_RS,
2, 0, 0);
- _ipu_dc_write_tmpl(0x64, WROD(0), 0, map, ASYNC_SER_WAVE, 0, 0);
+ _ipu_dc_write_tmpl(0x64, WROD(0), 0, map, ASYNC_SER_WAVE, 0, 0, 1);
/* Configure DC for serial panel */
__raw_writel(0x14, DC_DISP_CONF1(DC_DISP_ID_SERIAL));
@@ -1679,6 +1808,39 @@ int32_t ipu_disp_set_window_pos(ipu_channel_t channel, int16_t x_pos,
}
EXPORT_SYMBOL(ipu_disp_set_window_pos);
+int32_t ipu_disp_get_window_pos(ipu_channel_t channel, int16_t *x_pos,
+ int16_t *y_pos)
+{
+ u32 reg;
+ unsigned long lock_flags;
+ uint32_t flow = 0;
+
+ if (channel == MEM_FG_SYNC)
+ flow = DP_SYNC;
+ else if (channel == MEM_FG_ASYNC0)
+ flow = DP_ASYNC0;
+ else if (channel == MEM_FG_ASYNC1)
+ flow = DP_ASYNC1;
+ else
+ return -EINVAL;
+
+ if (!g_ipu_clk_enabled)
+ clk_enable(g_ipu_clk);
+ spin_lock_irqsave(&ipu_lock, lock_flags);
+
+ reg = __raw_readl(DP_FG_POS(flow));
+
+ *x_pos = (reg >> 16) & 0x7FF;
+ *y_pos = reg & 0x7FF;
+
+ spin_unlock_irqrestore(&ipu_lock, lock_flags);
+ if (!g_ipu_clk_enabled)
+ clk_disable(g_ipu_clk);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_disp_get_window_pos);
+
void ipu_disp_direct_write(ipu_channel_t channel, u32 value, u32 offset)
{
if (channel == DIRECT_ASYNC0)
diff --git a/drivers/mxc/ipu3/ipu_ic.c b/drivers/mxc/ipu3/ipu_ic.c
index 564fab0b699a..78c3a9228941 100644
--- a/drivers/mxc/ipu3/ipu_ic.c
+++ b/drivers/mxc/ipu3/ipu_ic.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -157,7 +157,6 @@ void _ipu_vdi_init(ipu_channel_t channel, ipu_channel_params_t *params)
{
uint32_t reg;
uint32_t pixel_fmt;
- bool top_field_0;
reg = ((params->mem_prp_vf_mem.in_height-1) << 16) |
(params->mem_prp_vf_mem.in_width-1);
@@ -186,19 +185,7 @@ void _ipu_vdi_init(ipu_channel_t channel, ipu_channel_params_t *params)
}
__raw_writel(reg, VDI_C);
- /* MED_MOTION and LOW_MOTION algorithm that are using 3 fields
- * should start presenting using the 2nd field.
- */
- if (((params->mem_prp_vf_mem.field_fmt == V4L2_FIELD_INTERLACED_TB) &&
- (params->mem_prp_vf_mem.motion_sel != HIGH_MOTION)) ||
- ((params->mem_prp_vf_mem.field_fmt == V4L2_FIELD_INTERLACED_BT) &&
- (params->mem_prp_vf_mem.motion_sel == HIGH_MOTION)))
- top_field_0 = false;
- else
- top_field_0 = true;
-
- /* Buffer selection toggle the value therefore init val is inverted. */
- _ipu_vdi_set_top_field_man(!top_field_0);
+ _ipu_vdi_set_top_field_man(false);
_ipu_vdi_set_motion(params->mem_prp_vf_mem.motion_sel);
@@ -227,13 +214,13 @@ void _ipu_ic_init_prpvf(ipu_channel_params_t *params, bool src_is_csi)
/* Setup horizontal resizing */
/* Upadeted for IC split case */
- if (!(params->mem_prp_vf_mem.out_resize_ratio)) {
+ if (!(params->mem_prp_vf_mem.outh_resize_ratio)) {
_calc_resize_coeffs(params->mem_prp_vf_mem.in_width,
params->mem_prp_vf_mem.out_width,
&resizeCoeff, &downsizeCoeff);
reg |= (downsizeCoeff << 14) | resizeCoeff;
} else
- reg |= params->mem_prp_vf_mem.out_resize_ratio;
+ reg |= params->mem_prp_vf_mem.outh_resize_ratio;
__raw_writel(reg, IC_PRP_VF_RSC);
@@ -349,13 +336,13 @@ void _ipu_ic_init_prpenc(ipu_channel_params_t *params, bool src_is_csi)
/* Setup horizontal resizing */
/* Upadeted for IC split case */
- if (!(params->mem_prp_enc_mem.out_resize_ratio)) {
+ if (!(params->mem_prp_enc_mem.outh_resize_ratio)) {
_calc_resize_coeffs(params->mem_prp_enc_mem.in_width,
params->mem_prp_enc_mem.out_width,
&resizeCoeff, &downsizeCoeff);
reg |= (downsizeCoeff << 14) | resizeCoeff;
} else
- reg |= params->mem_prp_enc_mem.out_resize_ratio;
+ reg |= params->mem_prp_enc_mem.outh_resize_ratio;
__raw_writel(reg, IC_PRP_ENC_RSC);
@@ -387,6 +374,8 @@ void _ipu_ic_init_prpenc(ipu_channel_params_t *params, bool src_is_csi)
ic_conf |= IC_CONF_RWS_EN;
__raw_writel(ic_conf, IC_CONF);
+
+// ic_dump_register();
}
void _ipu_ic_uninit_prpenc(void)
@@ -418,20 +407,24 @@ void _ipu_ic_init_pp(ipu_channel_params_t *params)
ipu_color_space_t in_fmt, out_fmt;
/* Setup vertical resizing */
- _calc_resize_coeffs(params->mem_pp_mem.in_height,
+ if (!(params->mem_pp_mem.outv_resize_ratio)) {
+ _calc_resize_coeffs(params->mem_pp_mem.in_height,
params->mem_pp_mem.out_height,
&resizeCoeff, &downsizeCoeff);
- reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
+ reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
+ } else {
+ reg = (params->mem_pp_mem.outv_resize_ratio) << 16;
+ }
/* Setup horizontal resizing */
/* Upadeted for IC split case */
- if (!(params->mem_pp_mem.out_resize_ratio)) {
+ if (!(params->mem_pp_mem.outh_resize_ratio)) {
_calc_resize_coeffs(params->mem_pp_mem.in_width,
params->mem_pp_mem.out_width,
&resizeCoeff, &downsizeCoeff);
reg |= (downsizeCoeff << 14) | resizeCoeff;
} else {
- reg |= params->mem_pp_mem.out_resize_ratio;
+ reg |= params->mem_pp_mem.outh_resize_ratio;
}
__raw_writel(reg, IC_PP_RSC);
diff --git a/drivers/mxc/ipu3/ipu_param_mem.h b/drivers/mxc/ipu3/ipu_param_mem.h
index dab3b617db1c..30e6dc1005ba 100644
--- a/drivers/mxc/ipu3/ipu_param_mem.h
+++ b/drivers/mxc/ipu3/ipu_param_mem.h
@@ -155,8 +155,15 @@ static inline void _ipu_ch_param_init(int ch,
ipu_ch_param_set_field(&params, 1, 102, 14, stride - 1);
}
+ /* EBA is 8-byte aligned */
ipu_ch_param_set_field(&params, 1, 0, 29, addr0 >> 3);
ipu_ch_param_set_field(&params, 1, 29, 29, addr1 >> 3);
+ if (addr0%8)
+ dev_warn(g_ipu_dev,
+ "IDMAC%d's EBA0 is not 8-byte aligned\n", ch);
+ if (addr1%8)
+ dev_warn(g_ipu_dev,
+ "IDMAC%d's EBA1 is not 8-byte aligned\n", ch);
switch (pixel_fmt) {
case IPU_PIX_FMT_GENERIC:
@@ -210,13 +217,14 @@ static inline void _ipu_ch_param_init(int ch,
case IPU_PIX_FMT_ABGR32:
ipu_ch_param_set_field(&params, 0, 107, 3, 0); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
_ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
break;
case IPU_PIX_FMT_UYVY:
ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
ipu_ch_param_set_field(&params, 1, 85, 4, 0xA); /* pix format */
- ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
break;
case IPU_PIX_FMT_YUYV:
ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
@@ -289,13 +297,19 @@ static inline void _ipu_ch_param_init(int ch,
v_offset = v;
}
- /* UBO and VBO are 22-bit */
+ /* UBO and VBO are 22-bit and 8-byte aligned */
if (u_offset/8 > 0x3fffff)
- dev_err(g_ipu_dev,
- "The value of U offset exceeds IPU limitation\n");
+ dev_warn(g_ipu_dev,
+ "IDMAC%d's U offset exceeds IPU limitation\n", ch);
if (v_offset/8 > 0x3fffff)
- dev_err(g_ipu_dev,
- "The value of V offset exceeds IPU limitation\n");
+ dev_warn(g_ipu_dev,
+ "IDMAC%d's V offset exceeds IPU limitation\n", ch);
+ if (u_offset%8)
+ dev_warn(g_ipu_dev,
+ "IDMAC%d's U offset is not 8-byte aligned\n", ch);
+ if (v_offset%8)
+ dev_warn(g_ipu_dev,
+ "IDMAC%d's V offset is not 8-byte aligned\n", ch);
ipu_ch_param_set_field(&params, 0, 46, 22, u_offset / 8);
ipu_ch_param_set_field(&params, 0, 68, 22, v_offset / 8);
@@ -386,6 +400,13 @@ static inline void _ipu_ch_param_set_interlaced_scan(uint32_t ch)
u32 stride;
ipu_ch_param_set_field(ipu_ch_param_addr(ch), 0, 113, 1, 1);
stride = ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 102, 14) + 1;
+ /* ILO is 20-bit and 8-byte aligned */
+ if (stride/8 > 0xfffff)
+ dev_warn(g_ipu_dev,
+ "IDMAC%d's ILO exceeds IPU limitation\n", ch);
+ if (stride%8)
+ dev_warn(g_ipu_dev,
+ "IDMAC%d's ILO is not 8-byte aligned\n", ch);
ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 58, 20, stride / 8);
stride *= 2;
ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 102, 14, stride - 1);
@@ -442,7 +463,7 @@ static inline void _ipu_ch_offset_update(int ch,
(uv_stride * vertical_offset / 2) +
horizontal_offset / 2;
v_offset = u_offset + (uv_stride * height / 2);
- u_fix = u ? (u + (uv_stride * vertical_offset) +
+ u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
(horizontal_offset / 2) -
(stride * vertical_offset) - (horizontal_offset)) :
u_offset;
@@ -493,9 +514,9 @@ static inline void _ipu_ch_offset_update(int ch,
uv_stride = stride;
u_offset = stride * (height - vertical_offset - 1) +
(stride - horizontal_offset) +
- (uv_stride * vertical_offset) +
+ (uv_stride * vertical_offset / 2) +
horizontal_offset;
- u_fix = u ? (u + (uv_stride * vertical_offset) +
+ u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
horizontal_offset -
(stride * vertical_offset) - (horizontal_offset)) :
u_offset;
@@ -514,13 +535,19 @@ static inline void _ipu_ch_offset_update(int ch,
if (v_fix > v_offset)
v_offset = v_fix;
- /* UBO and VBO are 22-bit */
+ /* UBO and VBO are 22-bit and 8-byte aligned */
if (u_offset/8 > 0x3fffff)
- dev_err(g_ipu_dev,
- "The value of U offset exceeds IPU limitation\n");
+ dev_warn(g_ipu_dev,
+ "IDMAC%d's U offset exceeds IPU limitation\n", ch);
if (v_offset/8 > 0x3fffff)
- dev_err(g_ipu_dev,
- "The value of V offset exceeds IPU limitation\n");
+ dev_warn(g_ipu_dev,
+ "IDMAC%d's V offset exceeds IPU limitation\n", ch);
+ if (u_offset%8)
+ dev_warn(g_ipu_dev,
+ "IDMAC%d's U offset is not 8-byte aligned\n", ch);
+ if (v_offset%8)
+ dev_warn(g_ipu_dev,
+ "IDMAC%d's V offset is not 8-byte aligned\n", ch);
ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 0, 46, 22, u_offset / 8);
ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 0, 68, 22, v_offset / 8);
diff --git a/drivers/mxc/ipu3/ipu_prv.h b/drivers/mxc/ipu3/ipu_prv.h
index 213ded04c87d..4e62b256889f 100644
--- a/drivers/mxc/ipu3/ipu_prv.h
+++ b/drivers/mxc/ipu3/ipu_prv.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -60,7 +60,7 @@ void _ipu_init_dc_mappings(void);
int _ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt,
uint32_t out_pixel_fmt);
void _ipu_dp_uninit(ipu_channel_t channel);
-void _ipu_dc_init(int dc_chan, int di, bool interlaced);
+void _ipu_dc_init(int dc_chan, int di, bool interlaced, uint32_t pixel_fmt);
void _ipu_dc_uninit(int dc_chan);
void _ipu_dp_dc_enable(ipu_channel_t channel);
void _ipu_dp_dc_disable(ipu_channel_t channel, bool swap);
diff --git a/drivers/mxc/ipu3/ipu_regs.h b/drivers/mxc/ipu3/ipu_regs.h
index 2438df60a0ce..4a78e14df560 100644
--- a/drivers/mxc/ipu3/ipu_regs.h
+++ b/drivers/mxc/ipu3/ipu_regs.h
@@ -261,6 +261,14 @@ extern u32 *ipu_vdi_reg;
#define DC_EVT_NEW_CHAN_R_1 9
#define DC_EVT_NEW_DATA_R_0 10
#define DC_EVT_NEW_DATA_R_1 11
+#define DC_EVEN_UGDE0 12
+#define DC_ODD_UGDE0 13
+#define DC_EVEN_UGDE1 14
+#define DC_ODD_UGDE1 15
+#define DC_EVEN_UGDE2 16
+#define DC_ODD_UGDE2 17
+#define DC_EVEN_UGDE3 18
+#define DC_ODD_UGDE3 19
#define dc_ch_offset(ch) \
({ \
@@ -627,6 +635,8 @@ enum {
VDI_C_VWM3_CLR_2 = 0x02000000,
VDI_C_TOP_FIELD_MAN_1 = 0x40000000,
VDI_C_TOP_FIELD_AUTO_1 = 0x80000000,
+
+ DMFC_FIFO_SIZE_5F = 0x00003800,
};
enum di_pins {
@@ -654,5 +664,6 @@ enum di_sync_wave {
/* DC template opcodes */
#define WROD(lf) (0x18 | (lf << 1))
+#define WRG (0x01)
#endif
diff --git a/drivers/mxc/mlb/Kconfig b/drivers/mxc/mlb/Kconfig
index 294c9776fb4d..7e3b16c2ddae 100644
--- a/drivers/mxc/mlb/Kconfig
+++ b/drivers/mxc/mlb/Kconfig
@@ -6,7 +6,7 @@ menu "MXC Media Local Bus Driver"
config MXC_MLB
tristate "MLB support"
- depends on ARCH_MX35
+ depends on ARCH_MX35 || ARCH_MX53
---help---
Say Y to get the MLB support.
diff --git a/drivers/mxc/pmic/core/mc13892.c b/drivers/mxc/pmic/core/mc13892.c
index 9f232a4f5718..1175ab633fc6 100644
--- a/drivers/mxc/pmic/core/mc13892.c
+++ b/drivers/mxc/pmic/core/mc13892.c
@@ -262,6 +262,7 @@ int pmic_event_unmask(type_event event)
return ret;
}
+EXPORT_SYMBOL(pmic_event_unmask);
int pmic_event_mask(type_event event)
{
@@ -294,7 +295,7 @@ int pmic_event_mask(type_event event)
return ret;
}
-
+EXPORT_SYMBOL(pmic_event_mask);
/*!
* This function returns the PMIC version in system.
*
diff --git a/drivers/mxc/pmic/core/pmic.h b/drivers/mxc/pmic/core/pmic.h
index 964c44a06bc1..da61b19a3f31 100644
--- a/drivers/mxc/pmic/core/pmic.h
+++ b/drivers/mxc/pmic/core/pmic.h
@@ -58,8 +58,6 @@ static inline int spi_rw(struct spi_device *spi, u8 * buf, size_t len)
.cs_change = 0,
.delay_usecs = 0,
};
- mxc_spi_poll_transfer(spi, &t);
- return 0;
#if 0
struct spi_message m;
@@ -68,6 +66,9 @@ static inline int spi_rw(struct spi_device *spi, u8 * buf, size_t len)
if (spi_sync(spi, &m) != 0 || m.status != 0)
return PMIC_ERROR;
return (len - m.actual_length);
+#else
+ mxc_spi_poll_transfer(spi, &t);
+ return 0;
#endif
}
diff --git a/drivers/mxc/pmic/mc13892/pmic_adc.c b/drivers/mxc/pmic/mc13892/pmic_adc.c
index 68588a40d7e4..60ce35e86a06 100644
--- a/drivers/mxc/pmic/mc13892/pmic_adc.c
+++ b/drivers/mxc/pmic/mc13892/pmic_adc.c
@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/device.h>
+#include <linux/cdev.h>
#include <linux/pmic_adc.h>
#include <linux/pmic_status.h>
@@ -33,6 +34,9 @@
#define MC13892_ADC0_TS_M_LSH 14
#define MC13892_ADC0_TS_M_WID 3
+static int pmic_adc_major;
+static struct class *pmic_adc_class;
+
/*
* Maximun allowed variation in the three X/Y co-ordinates acquired from
* touch-screen
@@ -924,17 +928,322 @@ static ssize_t adc_ctl(struct device *dev, struct device_attribute *attr,
#endif
+/*!
+ * This function triggers a conversion and returns sampling results of each
+ * specified channel.
+ *
+ * @param channels This input parameter is bitmap to specify channels
+ * to be sampled.
+ * @param result The pointer to array to store sampling results.
+ * The memory should be allocated by the caller of this
+ * function.
+ *
+ * @return This function returns PMIC_SUCCESS if successful.
+ */
+PMIC_STATUS pmic_adc_convert_multichnnel(t_channel channels,
+ unsigned short *result)
+{
+ t_adc_param adc_param;
+ int i;
+ PMIC_STATUS ret;
+ if (suspend_flag == 1) {
+ return -EBUSY;
+ }
+ mc13892_adc_init_param(&adc_param);
+ pr_debug("pmic_adc_convert_multichnnel\n");
+
+ channels = channel_num[channels];
+
+ if (channels == -1) {
+ pr_debug("Wrong channel ID\n");
+ return PMIC_PARAMETER_ERROR;
+ }
+
+ adc_param.read_ts = false;
+ adc_param.single_channel = false;
+ if ((channels >= 0) && (channels <= 7)) {
+ adc_param.channel_0 = channels;
+ adc_param.channel_1 = ((channels + 4) % 4) + 4;
+ } else {
+ return PMIC_PARAMETER_ERROR;
+ }
+ adc_param.read_mode = 0x00003f;
+ adc_param.read_ts = false;
+ ret = mc13892_adc_convert(&adc_param);
+
+ for (i = 0; i <= 7; i++) {
+ result[i] = adc_param.value[i];
+ }
+ return ret;
+}
+
+/*!
+ * This function starts a Battery Current mode conversion.
+ *
+ * @param mode Conversion mode.
+ * @param result Battery Current measurement result.
+ * if \a mode = ADC_8CHAN_1X, the result is \n
+ * result[0] = (BATTP - BATT_I) \n
+ * if \a mode = ADC_1CHAN_8X, the result is \n
+ * result[0] = BATTP \n
+ * result[1] = BATT_I \n
+ * result[2] = BATTP \n
+ * result[3] = BATT_I \n
+ * result[4] = BATTP \n
+ * result[5] = BATT_I \n
+ * result[6] = BATTP \n
+ * result[7] = BATT_I
+ *
+ * @return This function returns PMIC_SUCCESS if successful.
+ */
+PMIC_STATUS pmic_adc_get_battery_current(t_conversion_mode mode,
+ unsigned short *result)
+{
+ PMIC_STATUS ret;
+ t_channel channel;
+ if (suspend_flag == 1) {
+ return -EBUSY;
+ }
+ channel = BATTERY_CURRENT;
+ if (mode == ADC_8CHAN_1X) {
+ ret = pmic_adc_convert(channel, result);
+ } else {
+ ret = pmic_adc_convert_8x(channel, result);
+ }
+ return ret;
+}
+
+/*!
+ * This function implements the open method on a MC13892 ADC device.
+ *
+ * @param inode pointer on the node
+ * @param file pointer on the file
+ * @return This function returns 0.
+ */
+static int pmic_adc_open(struct inode *inode, struct file *file)
+{
+ while (suspend_flag == 1) {
+ swait++;
+ /* Block if the device is suspended */
+ if (wait_event_interruptible(suspendq, (suspend_flag == 0))) {
+ return -ERESTARTSYS;
+ }
+ }
+ pr_debug("mc13892_adc : mc13892_adc_open()\n");
+ return 0;
+}
+
+/*!
+ * This function implements the release method on a MC13892 ADC device.
+ *
+ * @param inode pointer on the node
+ * @param file pointer on the file
+ * @return This function returns 0.
+ */
+static int pmic_adc_free(struct inode *inode, struct file *file)
+{
+ pr_debug("mc13892_adc : mc13892_adc_free()\n");
+ return 0;
+}
+
+/*!
+ * This function implements IOCTL controls on a MC13892 ADC device.
+ *
+ * @param inode pointer on the node
+ * @param file pointer on the file
+ * @param cmd the command
+ * @param arg the parameter
+ * @return This function returns 0 if successful.
+ */
+static int pmic_adc_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ t_adc_convert_param *convert_param;
+ t_touch_mode touch_mode;
+ t_touch_screen touch_sample;
+ unsigned short b_current;
+
+ if ((_IOC_TYPE(cmd) != 'p') && (_IOC_TYPE(cmd) != 'D'))
+ return -ENOTTY;
+
+ while (suspend_flag == 1) {
+ swait++;
+ /* Block if the device is suspended */
+ if (wait_event_interruptible(suspendq, (suspend_flag == 0))) {
+ return -ERESTARTSYS;
+ }
+ }
+
+ switch (cmd) {
+ case PMIC_ADC_INIT:
+ CHECK_ERROR(pmic_adc_init());
+ break;
+
+ case PMIC_ADC_DEINIT:
+ CHECK_ERROR(pmic_adc_deinit());
+ break;
+
+ case PMIC_ADC_CONVERT:
+ if ((convert_param = kmalloc(sizeof(t_adc_convert_param),
+ GFP_KERNEL)) == NULL) {
+ return -ENOMEM;
+ }
+ if (copy_from_user(convert_param, (t_adc_convert_param *) arg,
+ sizeof(t_adc_convert_param))) {
+ kfree(convert_param);
+ return -EFAULT;
+ }
+ CHECK_ERROR_KFREE(pmic_adc_convert(convert_param->channel,
+ convert_param->result),
+ (kfree(convert_param)));
+
+ if (copy_to_user((t_adc_convert_param *) arg, convert_param,
+ sizeof(t_adc_convert_param))) {
+ kfree(convert_param);
+ return -EFAULT;
+ }
+ kfree(convert_param);
+ break;
+
+ case PMIC_ADC_CONVERT_8X:
+ if ((convert_param = kmalloc(sizeof(t_adc_convert_param),
+ GFP_KERNEL)) == NULL) {
+ return -ENOMEM;
+ }
+ if (copy_from_user(convert_param, (t_adc_convert_param *) arg,
+ sizeof(t_adc_convert_param))) {
+ kfree(convert_param);
+ return -EFAULT;
+ }
+ CHECK_ERROR_KFREE(pmic_adc_convert_8x(convert_param->channel,
+ convert_param->result),
+ (kfree(convert_param)));
+
+ if (copy_to_user((t_adc_convert_param *) arg, convert_param,
+ sizeof(t_adc_convert_param))) {
+ kfree(convert_param);
+ return -EFAULT;
+ }
+ kfree(convert_param);
+ break;
+
+ case PMIC_ADC_CONVERT_MULTICHANNEL:
+ if ((convert_param = kmalloc(sizeof(t_adc_convert_param),
+ GFP_KERNEL)) == NULL) {
+ return -ENOMEM;
+ }
+ if (copy_from_user(convert_param, (t_adc_convert_param *) arg,
+ sizeof(t_adc_convert_param))) {
+ kfree(convert_param);
+ return -EFAULT;
+ }
+
+ CHECK_ERROR_KFREE(pmic_adc_convert_multichnnel
+ (convert_param->channel,
+ convert_param->result),
+ (kfree(convert_param)));
+
+ if (copy_to_user((t_adc_convert_param *) arg, convert_param,
+ sizeof(t_adc_convert_param))) {
+ kfree(convert_param);
+ return -EFAULT;
+ }
+ kfree(convert_param);
+ break;
+
+ case PMIC_ADC_SET_TOUCH_MODE:
+ CHECK_ERROR(pmic_adc_set_touch_mode((t_touch_mode) arg));
+ break;
+
+ case PMIC_ADC_GET_TOUCH_MODE:
+ CHECK_ERROR(pmic_adc_get_touch_mode(&touch_mode));
+ if (copy_to_user((t_touch_mode *) arg, &touch_mode,
+ sizeof(t_touch_mode))) {
+ return -EFAULT;
+ }
+ break;
+
+ case PMIC_ADC_GET_TOUCH_SAMPLE:
+ CHECK_ERROR(pmic_adc_get_touch_sample(&touch_sample, 1));
+ if (copy_to_user((t_touch_screen *) arg, &touch_sample,
+ sizeof(t_touch_screen))) {
+ return -EFAULT;
+ }
+ break;
+
+ case PMIC_ADC_GET_BATTERY_CURRENT:
+ CHECK_ERROR(pmic_adc_get_battery_current(ADC_8CHAN_1X,
+ &b_current));
+ if (copy_to_user((unsigned short *)arg, &b_current,
+ sizeof(unsigned short))) {
+
+ return -EFAULT;
+ }
+ break;
+
+ default:
+ pr_debug("pmic_adc_ioctl: unsupported ioctl command 0x%x\n",
+ cmd);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct file_operations mc13892_adc_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = pmic_adc_ioctl,
+ .open = pmic_adc_open,
+ .release = pmic_adc_free,
+};
+
+static struct cdev pmic_adc_cdev;
static DEVICE_ATTR(adc, 0644, adc_info, adc_ctl);
static int pmic_adc_module_probe(struct platform_device *pdev)
{
int ret = 0;
+ struct device * sdev;
+ dev_t devid;
pr_debug("PMIC ADC start probe\n");
+
+ if( (ret = alloc_chrdev_region(&devid, 0, 8, "pmic_adc")) < 0 ) {
+ pr_debug(KERN_ERR "Unable to allocate device range for pmic_adc\n");
+ return ret;
+ }
+ pmic_adc_major = MAJOR(devid);
+ if (pmic_adc_major < 0) {
+ pr_debug(KERN_ERR "Unable to get a major for pmic_adc\n");
+ ret = pmic_adc_major;
+ goto unreg_char;
+ }
+
+ cdev_init(&pmic_adc_cdev, &mc13892_adc_fops);
+ ret =cdev_add(&pmic_adc_cdev, devid, 8);
+ if (ret < 0) {
+ pr_err("pmic_adc: cannot add character device\n");
+ goto unreg_char;
+ }
+
+ pmic_adc_class = class_create(THIS_MODULE, "pmic_adc");
+ if (IS_ERR(pmic_adc_class)) {
+ pr_debug(KERN_ERR "Error creating pmic_adc class.\n");
+ ret = PTR_ERR(pmic_adc_class);
+ goto unreg_char;
+ }
+
+ sdev = device_create(pmic_adc_class, NULL, devid, NULL, "pmic_adc");
+ if (IS_ERR(sdev) ) {
+ pr_debug(KERN_ERR "Error creating pmic_adc class device.\n");
+ ret = PTR_ERR(sdev);
+ goto cl_destroy;
+ }
+
ret = device_create_file(&(pdev->dev), &dev_attr_adc);
if (ret) {
pr_debug("Can't create device file!\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto dev_destroy;
}
init_waitqueue_head(&suspendq);
@@ -946,11 +1255,17 @@ static int pmic_adc_module_probe(struct platform_device *pdev)
}
pmic_adc_ready = 1;
- pr_debug("PMIC ADC successfully probed\n");
+ printk(KERN_DEBUG"PMIC ADC successfully probed\n");
return 0;
- rm_dev_file:
+rm_dev_file:
device_remove_file(&(pdev->dev), &dev_attr_adc);
+dev_destroy:
+ device_destroy(pmic_adc_class, MKDEV(pmic_adc_major, 0));
+cl_destroy:
+ class_destroy(pmic_adc_class);
+unreg_char:
+ unregister_chrdev(pmic_adc_major, "pmic_adc");
return ret;
}
diff --git a/drivers/mxc/pmic/mc13892/pmic_battery.c b/drivers/mxc/pmic/mc13892/pmic_battery.c
index 8535eb0a34e4..c355e0c4338f 100644
--- a/drivers/mxc/pmic/mc13892/pmic_battery.c
+++ b/drivers/mxc/pmic/mc13892/pmic_battery.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -104,6 +104,19 @@ enum chg_setting {
VI_PROGRAM_EN
};
+
+static unsigned int max_voltage_design = 3800000;
+module_param(max_voltage_design, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(max_voltage_design, "Maximum battery voltage by design.");
+
+static unsigned int min_voltage_design = 3300000;
+module_param(min_voltage_design, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(min_voltage_design, "Minimum battery voltage by design.");
+
+static unsigned int main_charger_current = 0x8; /* 720 mA */
+module_param(main_charger_current, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(main_charger_current, "Main charge path regulator current limit.");
+
static int pmic_set_chg_current(unsigned short curr)
{
unsigned int mask;
@@ -180,15 +193,35 @@ static int pmic_set_chg_misc(enum chg_setting type, unsigned short flag)
return 0;
}
+static void pmic_stop_charging(void)
+{
+ pmic_set_chg_misc(AUTO_CHG_DIS, 0);
+ pmic_set_chg_current(0);
+}
+
+static int pmic_restart_charging(void)
+{
+ pmic_set_chg_misc(BAT_TH_CHECK_DIS, 1);
+ pmic_set_chg_misc(AUTO_CHG_DIS, 0);
+ pmic_set_chg_misc(VI_PROGRAM_EN, 1);
+ pmic_set_chg_current(main_charger_current);
+ pmic_set_chg_misc(RESTART_CHG_STAT, 1);
+ return 0;
+}
+
static int pmic_get_batt_voltage(unsigned short *voltage)
{
t_channel channel;
unsigned short result[8];
+ pmic_stop_charging();
+
channel = BATTERY_VOLTAGE;
CHECK_ERROR(pmic_adc_convert(channel, result));
*voltage = result[0];
+ pmic_restart_charging();
+
return 0;
}
@@ -197,10 +230,14 @@ static int pmic_get_batt_current(unsigned short *curr)
t_channel channel;
unsigned short result[8];
+ pmic_stop_charging();
+
channel = BATTERY_CURRENT;
CHECK_ERROR(pmic_adc_convert(channel, result));
*curr = result[0];
+ pmic_restart_charging();
+
return 0;
}
@@ -284,16 +321,6 @@ static int pmic_get_charger_coulomb(int *coulomb)
return 0;
}
-static int pmic_restart_charging(void)
-{
- pmic_set_chg_misc(BAT_TH_CHECK_DIS, 1);
- pmic_set_chg_misc(AUTO_CHG_DIS, 0);
- pmic_set_chg_misc(VI_PROGRAM_EN, 1);
- pmic_set_chg_current(0x8);
- pmic_set_chg_misc(RESTART_CHG_STAT, 1);
- return 0;
-}
-
struct mc13892_dev_info {
struct device *dev;
@@ -353,8 +380,8 @@ static int mc13892_charger_update_status(struct mc13892_dev_info *di)
pmic_restart_charging();
} else
pmic_stop_coulomb_counter();
+ }
}
- }
return ret;
}
@@ -422,7 +449,7 @@ static void mc13892_battery_update_status(struct mc13892_dev_info *di)
else
di->battery_status =
POWER_SUPPLY_STATUS_NOT_CHARGING;
- }
+ }
if (di->battery_status == POWER_SUPPLY_STATUS_NOT_CHARGING)
di->full_counter++;
@@ -491,10 +518,10 @@ static int mc13892_battery_get_property(struct power_supply *psy,
val->intval = di->accum_current_uAh;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
- val->intval = 3800000;
+ val->intval = max_voltage_design;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
- val->intval = 3300000;
+ val->intval = min_voltage_design;
break;
default:
return -EINVAL;
@@ -536,7 +563,7 @@ static int pmic_battery_probe(struct platform_device *pdev)
pr_debug("Battery driver is only applied for MC13892 V2.0\n");
return -1;
}
- if (machine_is_mx51_babbage()) {
+ if (machine_is_mx51_babbage() || machine_is_mx50_arm2()) {
pr_debug("mc13892 charger is not used for this platform\n");
return -1;
}
diff --git a/drivers/mxc/security/Kconfig b/drivers/mxc/security/Kconfig
index 875848b2c69c..3e36a29ace64 100644
--- a/drivers/mxc/security/Kconfig
+++ b/drivers/mxc/security/Kconfig
@@ -27,6 +27,7 @@ config MXC_SECURITY_RNG
depends on ARCH_MXC
depends on !ARCH_MXC91321
depends on !ARCH_MX27
+ depends on !ARCH_MX51
default n
select MXC_SECURITY_CORE
---help---
diff --git a/drivers/mxc/security/sahara2/fsl_shw_auth.c b/drivers/mxc/security/sahara2/fsl_shw_auth.c
index d3100f01380a..b3f8788b553a 100644
--- a/drivers/mxc/security/sahara2/fsl_shw_auth.c
+++ b/drivers/mxc/security/sahara2/fsl_shw_auth.c
@@ -326,7 +326,7 @@ static inline fsl_shw_return_t add_assoc_preamble(sah_Head_Desc ** desc_chain,
return status;
} /* add_assoc_preamble() */
-#if SUPPORT_SSL
+#ifdef SUPPORT_SSL
/*!
* Generate an SSL value
*
@@ -473,7 +473,7 @@ fsl_shw_return_t fsl_shw_gen_encrypt(fsl_shw_uco_t * user_ctx,
SAH_SF_USER_CHECK();
if (auth_ctx->mode == FSL_ACC_MODE_SSL) {
-#if SUPPORT_SSL
+#ifdef SUPPORT_SSL
ret = do_ssl_gen(user_ctx, auth_ctx, cipher_key_info,
auth_key_info, auth_data_length, auth_data,
payload_length, payload, ct, auth_value);
diff --git a/drivers/mxc/security/scc2_driver.c b/drivers/mxc/security/scc2_driver.c
index 3249405c86a1..5c0d8b4dc26d 100644
--- a/drivers/mxc/security/scc2_driver.c
+++ b/drivers/mxc/security/scc2_driver.c
@@ -415,6 +415,7 @@ extern scc_partition_status_t scc_partition_status(void *part_base)
break;
}
}
+EXPORT_SYMBOL(scc_partition_status);
/**
* Calculate the physical address from the kernel virtual address.
@@ -427,6 +428,7 @@ uint32_t scc_virt_to_phys(void *address)
return (uint32_t) address - (uint32_t) scm_ram_base
+ (uint32_t) scm_ram_phys_base;
}
+EXPORT_SYMBOL(scc_virt_to_phys);
/**
* Engage partition of secure memory
diff --git a/drivers/mxc/vpu/mxc_vpu.c b/drivers/mxc/vpu/mxc_vpu.c
index b9ae23928c5d..9fc25edc33fa 100644
--- a/drivers/mxc/vpu/mxc_vpu.c
+++ b/drivers/mxc/vpu/mxc_vpu.c
@@ -73,6 +73,7 @@ static struct vpu_mem_desc user_data_mem = { 0 };
static struct vpu_mem_desc share_mem = { 0 };
static void __iomem *vpu_base;
+static int vpu_irq;
static u32 phy_vpu_base_addr;
static struct mxc_vpu_platform_data *vpu_plat;
@@ -539,7 +540,7 @@ static int vpu_map_mem(struct file *fp, struct vm_area_struct *vm)
request_size);
vm->vm_flags |= VM_IO | VM_RESERVED;
- vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
+ vm->vm_page_prot = pgprot_writecombine(vm->vm_page_prot);
return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff,
request_size, vm->vm_page_prot) ? -EAGAIN : 0;
@@ -635,8 +636,9 @@ static int vpu_dev_probe(struct platform_device *pdev)
err = -ENXIO;
goto err_out_class;
}
+ vpu_irq = res->start;
- err = request_irq(res->start, vpu_irq_handler, 0, "VPU_CODEC_IRQ",
+ err = request_irq(vpu_irq, vpu_irq_handler, 0, "VPU_CODEC_IRQ",
(void *)(&vpu_data));
if (err)
goto err_out_class;
@@ -660,6 +662,7 @@ static int vpu_dev_probe(struct platform_device *pdev)
static int vpu_dev_remove(struct platform_device *pdev)
{
+ free_irq(vpu_irq, &vpu_data);
iounmap(vpu_base);
iram_free(iram.start, VPU_IRAM_SIZE);
@@ -690,22 +693,25 @@ static int vpu_suspend(struct platform_device *pdev, pm_message_t state)
for (i = 0; i < vpu_clk_usercount; i++)
clk_disable(vpu_clk);
- clk_enable(vpu_clk);
- if (bitwork_mem.cpu_addr != 0) {
- SAVE_WORK_REGS;
- SAVE_CTRL_REGS;
- SAVE_RDWR_PTR_REGS;
- SAVE_DIS_FLAG_REGS;
-
- WRITE_REG(0x1, BIT_BUSY_FLAG);
- WRITE_REG(VPU_SLEEP_REG_VALUE, BIT_RUN_COMMAND);
- while (READ_REG(BIT_BUSY_FLAG)) ;
+ if (!cpu_is_mx37())
+ return 0;
+ else {
+ clk_enable(vpu_clk);
+ if (bitwork_mem.cpu_addr != 0) {
+ SAVE_WORK_REGS;
+ SAVE_CTRL_REGS;
+ SAVE_RDWR_PTR_REGS;
+ SAVE_DIS_FLAG_REGS;
+
+ WRITE_REG(0x1, BIT_BUSY_FLAG);
+ WRITE_REG(VPU_SLEEP_REG_VALUE, BIT_RUN_COMMAND);
+ while (READ_REG(BIT_BUSY_FLAG))
+ ;
+ }
+ clk_disable(vpu_clk);
}
- clk_disable(vpu_clk);
-
- if (cpu_is_mx37() || cpu_is_mx51())
- mxc_pg_enable(pdev);
+ mxc_pg_enable(pdev);
return 0;
@@ -719,11 +725,12 @@ static int vpu_resume(struct platform_device *pdev)
{
int i;
- if (cpu_is_mx37() || cpu_is_mx51())
+ if (cpu_is_mx37())
mxc_pg_disable(pdev);
+ else
+ goto recover_clk;
clk_enable(vpu_clk);
-
if (bitwork_mem.cpu_addr != 0) {
u32 *p = (u32 *) bitwork_mem.cpu_addr;
u32 data;
@@ -786,12 +793,13 @@ static int vpu_resume(struct platform_device *pdev)
WRITE_REG(VPU_WAKE_REG_VALUE, BIT_RUN_COMMAND);
while (READ_REG(BIT_BUSY_FLAG)) ;
}
-
clk_disable(vpu_clk);
+recover_clk:
/* Recover vpu clock */
for (i = 0; i < vpu_clk_usercount; i++)
clk_enable(vpu_clk);
+ printk("vpu_resume end\n");
return 0;
}
@@ -824,7 +832,6 @@ static int __init vpu_init(void)
static void __exit vpu_exit(void)
{
- free_irq(MXC_INT_VPU, (void *)(&vpu_data));
if (vpu_major > 0) {
device_destroy(vpu_class, MKDEV(vpu_major, 0));
class_destroy(vpu_class);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index bd5d0e026b02..28318f4236b1 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1885,6 +1885,13 @@ config FEC_1588
bool "Enable FEC 1588 timestamping"
depends on FEC
+config FEC_L2SWITCH
+ bool "L2 Switch Ethernet Controller (of ColdFire CPUs)"
+ depends on ARCH_MX28 && !FEC
+ help
+ Say Y here if you want to use the built-in 10/100 Ethernet Switch
+ Controller on some Motorola ColdFire processors.
+
config FEC2
bool "Second FEC ethernet controller (on some ColdFire CPUs)"
depends on FEC
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index f3c89fb1b799..11bb1b5623bf 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -115,6 +115,7 @@ obj-$(CONFIG_HP100) += hp100.o
obj-$(CONFIG_SMC9194) += smc9194.o
obj-$(CONFIG_FEC) += fec.o
obj-$(CONFIG_FEC_1588) += fec_1588.o
+obj-$(CONFIG_FEC_L2SWITCH) += fec_switch.o
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index a6bf9a7fddd9..481990fd3f2b 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -86,8 +86,8 @@ config CAN_DEBUG_DEVICES
config CAN_FLEXCAN
tristate "Freescale FlexCAN"
- depends on CAN && (ARCH_MX25 || ARCH_MX35 || ARCH_MX28)
- default m
+ depends on CAN && (ARCH_MX25 || ARCH_MX35 || ARCH_MX28 || ARCH_MX53)
+ default y
---help---
This select the support of Freescale CAN(FlexCAN).
This driver can also be built as a module.
diff --git a/drivers/net/can/flexcan/dev.c b/drivers/net/can/flexcan/dev.c
index 389f85d75709..404877c33eab 100644
--- a/drivers/net/can/flexcan/dev.c
+++ b/drivers/net/can/flexcan/dev.c
@@ -35,6 +35,74 @@
#endif
#include "flexcan.h"
+#define DEFAULT_BITRATE 500000
+#define TIME_SEGMENT_MIN 8
+#define TIME_SEGMENT_MAX 25
+#define TIME_SEGMENT_MID ((TIME_SEGMENT_MIN + TIME_SEGMENT_MAX)/2)
+
+struct time_segment {
+ char propseg;
+ char pseg1;
+ char pseg2;
+};
+
+struct time_segment time_segments[] = {
+ { /* total 8 timequanta */
+ 1, 2, 1
+ },
+ { /* total 9 timequanta */
+ 1, 2, 2
+ },
+ { /* total 10 timequanta */
+ 2, 2, 2
+ },
+ { /* total 11 timequanta */
+ 2, 2, 3
+ },
+ { /* total 12 timequanta */
+ 2, 3, 3
+ },
+ { /* total 13 timequanta */
+ 3, 3, 3
+ },
+ { /* total 14 timequanta */
+ 3, 3, 4
+ },
+ { /* total 15 timequanta */
+ 3, 4, 4
+ },
+ { /* total 16 timequanta */
+ 4, 4, 4
+ },
+ { /* total 17 timequanta */
+ 4, 4, 5
+ },
+ { /* total 18 timequanta */
+ 4, 5, 5
+ },
+ { /* total 19 timequanta */
+ 5, 5, 5
+ },
+ { /* total 20 timequanta */
+ 5, 5, 6
+ },
+ { /* total 21 timequanta */
+ 5, 6, 6
+ },
+ { /* total 22 timequanta */
+ 6, 6, 6
+ },
+ { /* total 23 timequanta */
+ 6, 6, 7
+ },
+ { /* total 24 timequanta */
+ 6, 7, 7
+ },
+ { /* total 25 timequanta */
+ 7, 7, 7
+ },
+};
+
enum {
FLEXCAN_ATTR_STATE = 0,
FLEXCAN_ATTR_BITRATE,
@@ -138,6 +206,45 @@ static void flexcan_set_bitrate(struct flexcan_device *flexcan, int bitrate)
* based on the bitrate to get the timing of
* presdiv, pseg1, pseg2, propseg
*/
+ int i, rate, div;
+ bool found = false;
+ struct time_segment *segment;
+ rate = clk_get_rate(flexcan->clk);
+
+ if (!bitrate)
+ bitrate = DEFAULT_BITRATE;
+
+ if (rate % bitrate == 0) {
+ div = rate / bitrate;
+ for (i = TIME_SEGMENT_MID; i <= TIME_SEGMENT_MAX; i++) {
+ if (div % i == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ for (i = TIME_SEGMENT_MID - 1;
+ i >= TIME_SEGMENT_MIN; i--) {
+ if (div % i == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ }
+ }
+
+ if (found) {
+ segment = &time_segments[i - TIME_SEGMENT_MIN];
+ flexcan->br_presdiv = div/i - 1;
+ flexcan->br_propseg = segment->propseg;
+ flexcan->br_pseg1 = segment->pseg1;
+ flexcan->br_pseg2 = segment->pseg2;
+ flexcan->bitrate = bitrate;
+ } else {
+ pr_info("The bitrate %d can't supported with clock \
+ rate of %d \n", bitrate, rate);
+ }
}
static void flexcan_update_bitrate(struct flexcan_device *flexcan)
@@ -201,7 +308,7 @@ static int flexcan_dump_xmit_mb(struct flexcan_device *flexcan, char *buf)
ret +=
sprintf(buf + ret,
"mb[%d]::CS:0x%x ID:0x%x DATA[1~2]:0x%02x,0x%02x\n",
- i, flexcan->hwmb[i].mb_cs.data,
+ i, flexcan->hwmb[i].mb_cs,
flexcan->hwmb[i].mb_id, flexcan->hwmb[i].mb_data[1],
flexcan->hwmb[i].mb_data[2]);
return ret;
@@ -214,7 +321,7 @@ static int flexcan_dump_rx_mb(struct flexcan_device *flexcan, char *buf)
ret +=
sprintf(buf + ret,
"mb[%d]::CS:0x%x ID:0x%x DATA[1~2]:0x%02x,0x%02x\n",
- i, flexcan->hwmb[i].mb_cs.data,
+ i, flexcan->hwmb[i].mb_cs,
flexcan->hwmb[i].mb_id, flexcan->hwmb[i].mb_data[1],
flexcan->hwmb[i].mb_data[2]);
return ret;
@@ -575,6 +682,7 @@ struct net_device *flexcan_device_alloc(struct platform_device *pdev,
return NULL;
}
flexcan_device_default(flexcan);
+ flexcan_set_bitrate(flexcan, flexcan->bitrate);
flexcan_update_bitrate(flexcan);
num = ARRAY_SIZE(flexcan_dev_attr);
diff --git a/drivers/net/can/flexcan/flexcan.h b/drivers/net/can/flexcan/flexcan.h
index d19cc1ee0620..51a800bd8e55 100644
--- a/drivers/net/can/flexcan/flexcan.h
+++ b/drivers/net/can/flexcan/flexcan.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -32,17 +32,6 @@
#define FLEXCAN_DEVICE_NAME "FlexCAN"
-struct can_mb_cs {
- unsigned int time_stamp:16;
- unsigned int length:4;
- unsigned int rtr:1;
- unsigned int ide:1;
- unsigned int srr:1;
- unsigned int nouse1:1;
- unsigned int code:4;
- unsigned int nouse2:4;
-};
-
#define CAN_MB_RX_INACTIVE 0x0
#define CAN_MB_RX_EMPTY 0x4
#define CAN_MB_RX_FULL 0x2
@@ -55,14 +44,24 @@ struct can_mb_cs {
#define CAN_MB_TX_REMOTE 0xA
struct can_hw_mb {
- union {
- struct can_mb_cs cs;
- unsigned int data;
- } mb_cs;
+ unsigned int mb_cs;
unsigned int mb_id;
unsigned char mb_data[8];
};
+#define MB_CS_CODE_OFFSET 24
+#define MB_CS_CODE_MASK (0xF << MB_CS_CODE_OFFSET)
+#define MB_CS_SRR_OFFSET 22
+#define MB_CS_SRR_MASK (0x1 << MB_CS_SRR_OFFSET)
+#define MB_CS_IDE_OFFSET 21
+#define MB_CS_IDE_MASK (0x1 << MB_CS_IDE_OFFSET)
+#define MB_CS_RTR_OFFSET 20
+#define MB_CS_RTR_MASK (0x1 << MB_CS_RTR_OFFSET)
+#define MB_CS_LENGTH_OFFSET 16
+#define MB_CS_LENGTH_MASK (0xF << MB_CS_LENGTH_OFFSET)
+#define MB_CS_TIMESTAMP_OFFSET 0
+#define MB_CS_TIMESTAMP_MASK (0xFF << MB_CS_TIMESTAMP_OFFSET)
+
#define CAN_HW_REG_MCR 0x00
#define CAN_HW_REG_CTRL 0x04
#define CAN_HW_REG_TIMER 0x08
diff --git a/drivers/net/can/flexcan/mbm.c b/drivers/net/can/flexcan/mbm.c
index b0341ba9128e..c846d97daadb 100644
--- a/drivers/net/can/flexcan/mbm.c
+++ b/drivers/net/can/flexcan/mbm.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -55,10 +55,13 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
hwmb = flexcan->hwmb + index;
if (flexcan->fifo || (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
- if (hwmb->mb_cs.cs.code == CAN_MB_TX_ABORT)
- hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ if ((hwmb->mb_cs & MB_CS_CODE_MASK) >> MB_CS_CODE_OFFSET ==
+ CAN_MB_TX_ABORT) {
+ hwmb->mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
+ }
- if (hwmb->mb_cs.cs.code & CAN_MB_TX_INACTIVE) {
+ if (hwmb->mb_cs & (CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET)) {
if (netif_queue_stopped(dev))
netif_start_queue(dev);
return;
@@ -68,16 +71,17 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
if (skb) {
frame = (struct can_frame *)skb_put(skb, sizeof(*frame));
memset(frame, 0, sizeof(*frame));
- if (hwmb->mb_cs.cs.ide)
+ if (hwmb->mb_cs & MB_CS_IDE_MASK)
frame->can_id =
(hwmb->mb_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
frame->can_id = (hwmb->mb_id >> 18) & CAN_SFF_MASK;
- if (hwmb->mb_cs.cs.rtr)
+ if (hwmb->mb_cs & MB_CS_RTR_MASK)
frame->can_id |= CAN_RTR_FLAG;
- frame->can_dlc = hwmb->mb_cs.cs.length;
+ frame->can_dlc =
+ (hwmb->mb_cs & MB_CS_LENGTH_MASK) >> MB_CS_LENGTH_OFFSET;
if (frame->can_dlc && frame->can_dlc)
flexcan_memcpy(frame->data, hwmb->mb_data,
@@ -85,7 +89,8 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
if (flexcan->fifo
|| (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
- hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ hwmb->mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
if (netif_queue_stopped(dev))
netif_start_queue(dev);
}
@@ -101,13 +106,13 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_rx(skb);
} else {
- tmp = hwmb->mb_cs.data;
+ tmp = hwmb->mb_cs;
tmp = hwmb->mb_id;
tmp = hwmb->mb_data[0];
if (flexcan->fifo
|| (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
-
- hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ hwmb->mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
if (netif_queue_stopped(dev))
netif_start_queue(dev);
}
@@ -131,17 +136,19 @@ static void flexcan_fifo_isr(struct net_device *dev, unsigned int iflag1)
frame =
(struct can_frame *)skb_put(skb, sizeof(*frame));
memset(frame, 0, sizeof(*frame));
- if (hwmb->mb_cs.cs.ide)
+ if (hwmb->mb_cs & MB_CS_IDE_MASK)
frame->can_id =
(hwmb->mb_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
frame->can_id =
(hwmb->mb_id >> 18) & CAN_SFF_MASK;
- if (hwmb->mb_cs.cs.rtr)
+ if (hwmb->mb_cs & MB_CS_RTR_MASK)
frame->can_id |= CAN_RTR_FLAG;
- frame->can_dlc = hwmb->mb_cs.cs.length;
+ frame->can_dlc =
+ (hwmb->mb_cs & MB_CS_LENGTH_MASK) >>
+ MB_CS_LENGTH_OFFSET;
if (frame->can_dlc && (frame->can_dlc <= 8))
flexcan_memcpy(frame->data, hwmb->mb_data,
@@ -158,7 +165,7 @@ static void flexcan_fifo_isr(struct net_device *dev, unsigned int iflag1)
skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_rx(skb);
} else {
- tmp = hwmb->mb_cs.data;
+ tmp = hwmb->mb_cs;
tmp = hwmb->mb_id;
tmp = hwmb->mb_data[0];
tmp = __raw_readl(flexcan->io_base + CAN_HW_REG_TIMER);
@@ -252,7 +259,8 @@ int flexcan_mbm_xmit(struct flexcan_device *flexcan, struct can_frame *frame)
struct can_hw_mb *hwmb = flexcan->hwmb;
do {
- if (hwmb[i].mb_cs.cs.code == CAN_MB_TX_INACTIVE)
+ if ((hwmb[i].mb_cs & MB_CS_CODE_MASK) >> MB_CS_CODE_OFFSET ==
+ CAN_MB_TX_INACTIVE)
break;
if ((++i) > flexcan->maxmb) {
if (flexcan->fifo)
@@ -273,22 +281,24 @@ int flexcan_mbm_xmit(struct flexcan_device *flexcan, struct can_frame *frame)
}
if (frame->can_id & CAN_RTR_FLAG)
- hwmb[i].mb_cs.cs.rtr = 1;
+ hwmb[i].mb_cs |= 1 << MB_CS_RTR_OFFSET;
else
- hwmb[i].mb_cs.cs.rtr = 0;
+ hwmb[i].mb_cs &= ~MB_CS_RTR_MASK;
if (frame->can_id & CAN_EFF_FLAG) {
- hwmb[i].mb_cs.cs.ide = 1;
- hwmb[i].mb_cs.cs.srr = 1;
+ hwmb[i].mb_cs |= 1 << MB_CS_IDE_OFFSET;
+ hwmb[i].mb_cs |= 1 << MB_CS_SRR_OFFSET;
hwmb[i].mb_id = frame->can_id & CAN_EFF_MASK;
} else {
- hwmb[i].mb_cs.cs.ide = 0;
+ hwmb[i].mb_cs &= ~MB_CS_IDE_MASK;
hwmb[i].mb_id = (frame->can_id & CAN_SFF_MASK) << 18;
}
- hwmb[i].mb_cs.cs.length = frame->can_dlc;
+ hwmb[i].mb_cs &= ~MB_CS_LENGTH_MASK;
+ hwmb[i].mb_cs |= frame->can_dlc << MB_CS_LENGTH_OFFSET;
flexcan_memcpy(hwmb[i].mb_data, frame->data, frame->can_dlc);
- hwmb[i].mb_cs.cs.code = CAN_MB_TX_ONCE;
+ hwmb[i].mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb[i].mb_cs |= CAN_MB_TX_ONCE << MB_CS_CODE_OFFSET;
return 0;
}
@@ -325,23 +335,27 @@ void flexcan_mbm_init(struct flexcan_device *flexcan)
id_table[i] = 0;
} else {
for (i = 0; i < rx_mb; i++) {
- hwmb[i].mb_cs.cs.code = CAN_MB_RX_EMPTY;
+ hwmb[i].mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb[i].mb_cs |= CAN_MB_RX_EMPTY << MB_CS_CODE_OFFSET;
/*
* IDE bit can not control by mask registers
* So set message buffer to receive extend
* or standard message.
*/
- if (flexcan->ext_msg && flexcan->std_msg)
- hwmb[i].mb_cs.cs.ide = i & 1;
- else {
+ if (flexcan->ext_msg && flexcan->std_msg) {
+ hwmb[i].mb_cs &= ~MB_CS_IDE_MASK;
+ hwmb[i].mb_cs |= (i & 1) << MB_CS_IDE_OFFSET;
+ } else {
if (flexcan->ext_msg)
- hwmb[i].mb_cs.cs.ide = 1;
+ hwmb[i].mb_cs |= 1 << MB_CS_IDE_OFFSET;
}
}
}
- for (; i <= flexcan->maxmb; i++)
- hwmb[i].mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ for (; i <= flexcan->maxmb; i++) {
+ hwmb[i].mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb[i].mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
+ }
flexcan->xmit_mb = rx_mb;
}
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index 582eb37390ed..8a34f4679fa5 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -30,8 +30,6 @@
#include <linux/delay.h>
#include <linux/spi/spi.h>
-#include <mach/platform.h>
-
#include "enc28j60_hw.h"
#define DRV_NAME "enc28j60"
@@ -53,9 +51,17 @@
#define MAX_TX_RETRYCOUNT 16
#ifdef CONFIG_ARCH_STMP3XXX
+#include <mach/platform.h>
#include <mach/stmp3xxx.h>
#include <mach/regs-ocotp.h>
#endif
+#ifdef CONFIG_ARCH_MXS
+#include <mach/system.h>
+#include <mach/hardware.h>
+#include <mach/regs-ocotp.h>
+#define REGS_OCOTP_BASE IO_ADDRESS(OCOTP_PHYS_ADDR)
+#endif
+
enum {
RXFILTER_NORMAL,
RXFILTER_MULTI,
@@ -104,12 +110,14 @@ static int enc28j60_get_mac(unsigned char *dev_addr, int idx)
return false;
if (!mac[idx]) {
-#ifdef CONFIG_ARCH_STMP3XXX
+#if defined(CONFIG_ARCH_STMP3XXX) || defined(CONFIG_ARCH_MXS)
if (get_evk_board_version() >= 1) {
int mac1 , mac2 , retry = 0;
- stmp3xxx_setl(BM_OCOTP_CTRL_RD_BANK_OPEN, REGS_OCOTP_BASE + HW_OCOTP_CTRL);
- while (__raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL) & BM_OCOTP_CTRL_BUSY) {
+ __raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN,
+ REGS_OCOTP_BASE + HW_OCOTP_CTRL_SET);
+ while (__raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL) &
+ BM_OCOTP_CTRL_BUSY) {
msleep(10);
retry++;
if (retry > 10)
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 46799e092bc1..206be36f0d19 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -296,6 +296,17 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
bufaddr = fep->tx_bounce[index];
}
+ if (fep->ptimer_present) {
+ if (fec_ptp_do_txstamp(skb))
+ estatus = BD_ENET_TX_TS;
+ else
+ estatus = 0;
+#ifdef CONFIG_FEC_1588
+ bdp->cbd_esc = (estatus | BD_ENET_TX_INT);
+ bdp->cbd_bdu = 0;
+#endif
+ }
+
#ifdef CONFIG_ARCH_MXS
swap_buffer(bufaddr, skb->len);
#endif
@@ -318,16 +329,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
| BD_ENET_TX_LAST | BD_ENET_TX_TC);
bdp->cbd_sc = status;
- if (fep->ptimer_present) {
- if (fec_ptp_do_txstamp(skb))
- estatus = BD_ENET_TX_TS;
- else
- estatus = 0;
-#ifdef CONFIG_FEC_1588
- bdp->cbd_esc = (estatus | BD_ENET_TX_INT);
- bdp->cbd_bdu = 0;
-#endif
- }
dev->trans_start = jiffies;
/* Trigger transmission start */
@@ -807,7 +808,7 @@ static struct mii_bus *fec_enet_mii_init(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(dev);
- struct fec_enet_platform_data *pdata;
+ struct fec_platform_data *pdata;
int err = -ENXIO, i;
fep->mii_timeout = 0;
@@ -836,6 +837,7 @@ static struct mii_bus *fec_enet_mii_init(struct platform_device *pdev)
fep->mii_bus->priv = fep;
fep->mii_bus->parent = &pdev->dev;
pdata = pdev->dev.platform_data;
+ fep->mii_bus->phy_mask = pdata->phy_mask;
fep->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
if (!fep->mii_bus->irq) {
@@ -1131,17 +1133,18 @@ fec_set_mac_address(struct net_device *dev, void *p)
{
struct fec_enet_private *fep = netdev_priv(dev);
struct sockaddr *addr = p;
+ u32 temp_mac[2];
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- writel(dev->dev_addr[3] | (dev->dev_addr[2] << 8) |
- (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24),
- fep->hwp + FEC_ADDR_LOW);
- writel((dev->dev_addr[5] << 16) | (dev->dev_addr[4] << 24),
- fep + FEC_ADDR_HIGH);
+ memcpy(&temp_mac, dev->dev_addr, ETH_ALEN);
+
+ writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW);
+ writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
+
return 0;
}
@@ -1277,6 +1280,7 @@ fec_restart(struct net_device *dev, int duplex)
/* Clear any outstanding interrupt. */
writel(0xffc00000, fep->hwp + FEC_IEVENT);
+#if !defined(CONFIG_MACH_CCMX51JS) && !defined(CONFIG_MACH_CCWMX51JS)
/* Reset all multicast. */
writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
@@ -1284,6 +1288,7 @@ fec_restart(struct net_device *dev, int duplex)
writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
#endif
+#endif /* !defined(CONFIG_MACH_CCMX51JS) && !defined(CONFIG_MACH_CCWMX51JS) */
#ifndef CONFIG_ARCH_MXS
if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) {
@@ -1407,6 +1412,15 @@ fec_stop(struct net_device *dev)
writel(1, fep->hwp + FEC_ECNTRL);
udelay(10);
+#ifdef CONFIG_ARCH_MXS
+ /* Check MII or RMII */
+ if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
+ writel(readl(fep->hwp + FEC_R_CNTRL) | 0x100,
+ fep->hwp + FEC_R_CNTRL);
+ else
+ writel(readl(fep->hwp + FEC_R_CNTRL) & ~0x100,
+ fep->hwp + FEC_R_CNTRL);
+#endif
/* Clear outstanding MII command interrupts. */
writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
@@ -1482,6 +1496,18 @@ fec_probe(struct platform_device *pdev)
fep->phy_interface = pdata->phy;
if (pdata->init && pdata->init())
goto failed_platform_init;
+
+ /*
+ * The priority for getting MAC address is:
+ * (1) kernel command line fec_mac = xx:xx:xx...
+ * (2) platform data mac field got from fuse etc
+ * (3) bootloader set the FEC mac register
+ */
+
+ if (!is_valid_ether_addr(fec_mac_default) &&
+ pdata->mac && is_valid_ether_addr(pdata->mac))
+ memcpy(fec_mac_default, pdata->mac,
+ sizeof(fec_mac_default));
} else
fep->phy_interface = PHY_INTERFACE_MODE_MII;
@@ -1499,10 +1525,10 @@ fec_probe(struct platform_device *pdev)
fep->mii_bus = fec_mii_bus;
}
- fep->ptp_priv = kmalloc(sizeof(struct fec_ptp_private), GFP_KERNEL);
+ fep->ptp_priv = kzalloc(sizeof(struct fec_ptp_private), GFP_KERNEL);
if (fep->ptp_priv) {
fep->ptp_priv->hwp = fep->hwp;
- ret = fec_ptp_init(fep->ptp_priv);
+ ret = fec_ptp_init(fep->ptp_priv, pdev->id);
if (ret)
printk(KERN_WARNING
"IEEE1588: ptp-timer is unavailable\n");
diff --git a/drivers/net/fec_1588.c b/drivers/net/fec_1588.c
index 5babcc29de78..c4bf278c7f19 100644
--- a/drivers/net/fec_1588.c
+++ b/drivers/net/fec_1588.c
@@ -35,7 +35,7 @@
static DECLARE_WAIT_QUEUE_HEAD(ptp_rx_ts_wait);
#define PTP_GET_RX_TIMEOUT (HZ/10)
-static struct fec_ptp_private *ptp_private;
+static struct fec_ptp_private *ptp_private[2];
/* Alloc the ring resource */
static int fec_ptp_init_circ(struct circ_buf *ptp_buf)
@@ -88,14 +88,15 @@ static int fec_ptp_is_full(struct circ_buf *buf)
}
static int fec_ptp_insert(struct circ_buf *ptp_buf,
- struct fec_ptp_data_t *data)
+ struct fec_ptp_data_t *data,
+ struct fec_ptp_private *priv)
{
struct fec_ptp_data_t *tmp;
if (fec_ptp_is_full(ptp_buf))
return 1;
- spin_lock(&ptp_private->ptp_lock);
+ spin_lock(&priv->ptp_lock);
tmp = (struct fec_ptp_data_t *)(ptp_buf->buf) + ptp_buf->tail;
tmp->key = data->key;
@@ -104,13 +105,15 @@ static int fec_ptp_insert(struct circ_buf *ptp_buf,
ptp_buf->tail = fec_ptp_calc_index(DEFAULT_PTP_RX_BUF_SZ,
ptp_buf->tail, 1);
- spin_unlock(&ptp_private->ptp_lock);
+ spin_unlock(&priv->ptp_lock);
return 0;
}
static int fec_ptp_find_and_remove(struct circ_buf *ptp_buf,
- int key, struct fec_ptp_data_t *data)
+ int key,
+ struct fec_ptp_data_t *data,
+ struct fec_ptp_private *priv)
{
int i;
int size = DEFAULT_PTP_RX_BUF_SZ;
@@ -129,10 +132,10 @@ static int fec_ptp_find_and_remove(struct circ_buf *ptp_buf,
i = fec_ptp_calc_index(size, i, 1);
}
- spin_lock_irqsave(&ptp_private->ptp_lock, flags);
+ spin_lock_irqsave(&priv->ptp_lock, flags);
if (i == end) {
ptp_buf->head = end;
- spin_unlock_irqrestore(&ptp_private->ptp_lock, flags);
+ spin_unlock_irqrestore(&priv->ptp_lock, flags);
return 1;
}
@@ -140,7 +143,7 @@ static int fec_ptp_find_and_remove(struct circ_buf *ptp_buf,
data->ts_time.nsec = tmp->ts_time.nsec;
ptp_buf->head = fec_ptp_calc_index(size, i, 1);
- spin_unlock_irqrestore(&ptp_private->ptp_lock, flags);
+ spin_unlock_irqrestore(&priv->ptp_lock, flags);
return 0;
}
@@ -154,9 +157,9 @@ int fec_ptp_start(struct fec_ptp_private *priv)
writel(FEC_T_CTRL_RESTART, fpp->hwp + FEC_ATIME_CTRL);
writel(FEC_T_INC_40MHZ << FEC_T_INC_OFFSET, fpp->hwp + FEC_ATIME_INC);
writel(FEC_T_PERIOD_ONE_SEC, fpp->hwp + FEC_ATIME_EVT_PERIOD);
- writel(FEC_T_CTRL_PERIOD_RST, fpp->hwp + FEC_ATIME_CTRL);
/* start counter */
- writel(FEC_T_CTRL_ENABLE, fpp->hwp + FEC_ATIME_CTRL);
+ writel(FEC_T_CTRL_PERIOD_RST | FEC_T_CTRL_ENABLE,
+ fpp->hwp + FEC_ATIME_CTRL);
return 0;
}
@@ -175,12 +178,19 @@ void fec_ptp_stop(struct fec_ptp_private *priv)
static void fec_get_curr_cnt(struct fec_ptp_private *priv,
struct ptp_rtc_time *curr_time)
{
+ u32 tempval;
+
+ writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL);
writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL);
curr_time->rtc_time.nsec = readl(priv->hwp + FEC_ATIME);
curr_time->rtc_time.sec = priv->prtc;
+
writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL);
- if (readl(priv->hwp + FEC_ATIME) < curr_time->rtc_time.nsec)
- curr_time->rtc_time.sec++;
+ tempval = readl(priv->hwp + FEC_ATIME);
+ if (tempval < curr_time->rtc_time.nsec) {
+ curr_time->rtc_time.nsec = tempval;
+ curr_time->rtc_time.sec = priv->prtc;
+ }
}
/* Set the 1588 timer counter registers */
@@ -190,12 +200,12 @@ static void fec_set_1588cnt(struct fec_ptp_private *priv,
u32 tempval;
unsigned long flags;
- spin_lock_irqsave(&ptp_private->cnt_lock, flags);
+ spin_lock_irqsave(&priv->cnt_lock, flags);
priv->prtc = fec_time->rtc_time.sec;
tempval = fec_time->rtc_time.nsec;
writel(tempval, priv->hwp + FEC_ATIME);
- spin_unlock_irqrestore(&ptp_private->cnt_lock, flags);
+ spin_unlock_irqrestore(&priv->cnt_lock, flags);
}
/* Set the BD to ptp */
@@ -207,11 +217,11 @@ int fec_ptp_do_txstamp(struct sk_buff *skb)
if (skb->len > 44) {
/* Check if port is 319 for PTP Event, and check for UDP */
iph = ip_hdr(skb);
- if (iph->protocol != FEC_PACKET_TYPE_UDP)
+ if (iph == NULL || iph->protocol != FEC_PACKET_TYPE_UDP)
return 0;
udph = udp_hdr(skb);
- if (udph->source == 319)
+ if (udph != NULL && ntohs(udph->source) == 319)
return 1;
}
@@ -244,24 +254,24 @@ void fec_ptp_store_rxstamp(struct fec_ptp_private *priv,
return;
udph = (struct udphdr *)(skb->data + FEC_PTP_UDP_OFFS);
- if (udph->source != 319)
+ if (ntohs(udph->source) != 319)
return;
seq_id = *((u16 *)(skb->data + FEC_PTP_SEQ_ID_OFFS));
control = *((u8 *)(skb->data + FEC_PTP_CTRL_OFFS));
- tmp_rx_time.key = seq_id;
+ tmp_rx_time.key = ntohs(seq_id);
tmp_rx_time.ts_time.sec = fpp->prtc;
tmp_rx_time.ts_time.nsec = bdp->ts;
switch (control) {
case PTP_MSG_SYNC:
- fec_ptp_insert(&(priv->rx_time_sync), &tmp_rx_time);
+ fec_ptp_insert(&(priv->rx_time_sync), &tmp_rx_time, priv);
break;
case PTP_MSG_DEL_REQ:
- fec_ptp_insert(&(priv->rx_time_del_req), &tmp_rx_time);
+ fec_ptp_insert(&(priv->rx_time_del_req), &tmp_rx_time, priv);
break;
/* clear transportSpecific field*/
@@ -271,11 +281,11 @@ void fec_ptp_store_rxstamp(struct fec_ptp_private *priv,
switch (msg_type) {
case PTP_MSG_P_DEL_REQ:
fec_ptp_insert(&(priv->rx_time_pdel_req),
- &tmp_rx_time);
+ &tmp_rx_time, priv);
break;
case PTP_MSG_P_DEL_RESP:
fec_ptp_insert(&(priv->rx_time_pdel_resp),
- &tmp_rx_time);
+ &tmp_rx_time, priv);
break;
default:
break;
@@ -308,20 +318,20 @@ static uint8_t fec_get_rx_time(struct fec_ptp_private *priv,
switch (mode) {
case PTP_MSG_SYNC:
flag = fec_ptp_find_and_remove(&(priv->rx_time_sync),
- key, &tmp);
+ key, &tmp, priv);
break;
case PTP_MSG_DEL_REQ:
flag = fec_ptp_find_and_remove(&(priv->rx_time_del_req),
- key, &tmp);
+ key, &tmp, priv);
break;
case PTP_MSG_P_DEL_REQ:
flag = fec_ptp_find_and_remove(&(priv->rx_time_pdel_req),
- key, &tmp);
+ key, &tmp, priv);
break;
case PTP_MSG_P_DEL_RESP:
flag = fec_ptp_find_and_remove(&(priv->rx_time_pdel_resp),
- key, &tmp);
+ key, &tmp, priv);
break;
default:
@@ -341,19 +351,19 @@ static uint8_t fec_get_rx_time(struct fec_ptp_private *priv,
switch (mode) {
case PTP_MSG_SYNC:
flag = fec_ptp_find_and_remove(&(priv->rx_time_sync),
- key, &tmp);
+ key, &tmp, priv);
break;
case PTP_MSG_DEL_REQ:
flag = fec_ptp_find_and_remove(
- &(priv->rx_time_del_req), key, &tmp);
+ &(priv->rx_time_del_req), key, &tmp, priv);
break;
case PTP_MSG_P_DEL_REQ:
flag = fec_ptp_find_and_remove(
- &(priv->rx_time_pdel_req), key, &tmp);
+ &(priv->rx_time_pdel_req), key, &tmp, priv);
break;
case PTP_MSG_P_DEL_RESP:
flag = fec_ptp_find_and_remove(
- &(priv->rx_time_pdel_resp), key, &tmp);
+ &(priv->rx_time_pdel_resp), key, &tmp, priv);
break;
}
@@ -367,6 +377,75 @@ static uint8_t fec_get_rx_time(struct fec_ptp_private *priv,
}
}
+static void fec_handle_ptpdrift(struct ptp_set_comp *comp,
+ struct ptp_time_correct *ptc)
+{
+ u32 ndrift;
+ u32 i;
+ u32 tmp, tmp_ns, tmp_prid;
+ u32 min_ns, min_prid, miss_ns;
+
+ ndrift = comp->drift;
+ if (ndrift == 0) {
+ ptc->corr_inc = 0;
+ ptc->corr_period = 0;
+ return;
+ }
+
+ if (ndrift >= FEC_ATIME_40MHZ) {
+ ptc->corr_inc = (u32)(ndrift / FEC_ATIME_40MHZ);
+ ptc->corr_period = 1;
+ return;
+ }
+
+ min_ns = 1;
+ tmp = FEC_ATIME_40MHZ % ndrift;
+ tmp_prid = (u32)(FEC_ATIME_40MHZ / ndrift);
+ min_prid = tmp_prid;
+ miss_ns = tmp / tmp_prid;
+ for (i = 2; i <= FEC_T_INC_40MHZ; i++) {
+ tmp = (FEC_ATIME_40MHZ * i) % ndrift;
+ tmp_prid = (FEC_ATIME_40MHZ * i) / ndrift;
+ tmp_ns = tmp / tmp_prid;
+ if (tmp_ns <= 10) {
+ min_ns = i;
+ min_prid = tmp_prid;
+ break;
+ }
+ if (tmp_ns < miss_ns) {
+ min_ns = i;
+ min_prid = tmp_prid;
+ miss_ns = tmp_ns;
+ }
+ }
+
+ ptc->corr_inc = min_ns;
+ ptc->corr_period = min_prid;
+}
+
+static void fec_set_drift(struct fec_ptp_private *priv,
+ struct ptp_set_comp *comp)
+{
+ struct ptp_time_correct tc;
+ struct fec_ptp_private *fpp = priv;
+ u32 tmp, corr_ns;
+
+ fec_handle_ptpdrift(comp, &tc);
+ if (tc.corr_inc == 0)
+ return;
+
+ if (comp->o_ops == TRUE)
+ corr_ns = FEC_T_INC_40MHZ + tc.corr_inc;
+ else
+ corr_ns = FEC_T_INC_40MHZ - tc.corr_inc;
+
+ tmp = readl(fpp->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK;
+ tmp |= corr_ns << FEC_T_INC_CORR_OFFSET;
+ writel(tmp, fpp->hwp + FEC_ATIME_INC);
+
+ writel(tc.corr_period, fpp->hwp + FEC_ATIME_CORR);
+}
+
static int ptp_open(struct inode *inode, struct file *file)
{
return 0;
@@ -387,10 +466,12 @@ static int ptp_ioctl(
struct ptp_rtc_time curr_time;
struct ptp_time rx_time, tx_time;
struct ptp_ts_data *p_ts;
+ struct ptp_set_comp *p_comp;
struct fec_ptp_private *priv;
+ unsigned int minor = MINOR(inode->i_rdev);
int retval = 0;
- priv = (struct fec_ptp_private *) ptp_private;
+ priv = (struct fec_ptp_private *) ptp_private[minor];
switch (cmd) {
case PTP_GET_RX_TIMESTAMP:
p_ts = (struct ptp_ts_data *)arg;
@@ -428,10 +509,11 @@ static int ptp_ioctl(
priv->rx_time_pdel_resp.tail = 0;
break;
case PTP_SET_COMPENSATION:
- /* TBD */
+ p_comp = (struct ptp_set_comp *)arg;
+ fec_set_drift(priv, p_comp);
break;
case PTP_GET_ORIG_COMP:
- /* TBD */
+ ((struct ptp_get_comp *)arg)->dw_origcomp = FEC_PTP_ORIG_COMP;
break;
default:
return -EINVAL;
@@ -466,7 +548,7 @@ static void ptp_free(void)
/*
* Resource required for accessing 1588 Timer Registers.
*/
-int fec_ptp_init(struct fec_ptp_private *priv)
+int fec_ptp_init(struct fec_ptp_private *priv, int id)
{
fec_ptp_init_circ(&(priv->rx_time_sync));
fec_ptp_init_circ(&(priv->rx_time_del_req));
@@ -475,8 +557,9 @@ int fec_ptp_init(struct fec_ptp_private *priv)
spin_lock_init(&priv->ptp_lock);
spin_lock_init(&priv->cnt_lock);
- ptp_private = priv;
- init_ptp();
+ ptp_private[id] = priv;
+ if (id == 0)
+ init_ptp();
return 0;
}
EXPORT_SYMBOL(fec_ptp_init);
diff --git a/drivers/net/fec_1588.h b/drivers/net/fec_1588.h
index 55b1a8c995bd..800ff310668f 100644
--- a/drivers/net/fec_1588.h
+++ b/drivers/net/fec_1588.h
@@ -24,6 +24,9 @@
#include <linux/circ_buf.h>
+#define FALSE 0
+#define TRUE 1
+
/* FEC 1588 register bits */
#define FEC_T_CTRL_CAPTURE 0x00000800
#define FEC_T_CTRL_RESTART 0x00000200
@@ -32,8 +35,11 @@
#define FEC_T_INC_MASK 0x0000007f
#define FEC_T_INC_OFFSET 0
+#define FEC_T_INC_CORR_MASK 0x00007f00
+#define FEC_T_INC_CORR_OFFSET 8
-#define FEC_T_INC_40MHZ 20
+#define FEC_T_INC_40MHZ 25
+#define FEC_ATIME_40MHZ 40000000
#define FEC_T_PERIOD_ONE_SEC 0x3B9ACA00
@@ -52,7 +58,7 @@
#define PTP_MSG_ALL_OTHER 0x5
#define PTP_GET_TX_TIMESTAMP 0x1
-#define PTP_GET_RX_TIMESTAMP 0x2
+#define PTP_GET_RX_TIMESTAMP 0x9
#define PTP_SET_RTC_TIME 0x3
#define PTP_SET_COMPENSATION 0x4
#define PTP_GET_CURRENT_TIME 0x5
@@ -64,13 +70,15 @@
#define PTP_GET_RX_TIMESTAMP_PDELAY_RESP 0xD
#define FEC_PTP_DOMAIN_DLFT 0xe0000181
-#define FEC_PTP_IP_OFFS 0xE
-#define FEC_PTP_UDP_OFFS 0x22
-#define FEC_PTP_MSG_TYPE_OFFS 0x2A
-#define FEC_PTP_SEQ_ID_OFFS 0x48
-#define FEC_PTP_CTRL_OFFS 0x4A
+#define FEC_PTP_IP_OFFS 0x0
+#define FEC_PTP_UDP_OFFS 0x14
+#define FEC_PTP_MSG_TYPE_OFFS 0x1C
+#define FEC_PTP_SEQ_ID_OFFS 0x3A
+#define FEC_PTP_CTRL_OFFS 0x3C
#define FEC_PACKET_TYPE_UDP 0x11
+#define FEC_PTP_ORIG_COMP 0x15555555
+
/* PTP standard time representation structure */
struct ptp_time{
u64 sec; /* seconds */
@@ -102,6 +110,31 @@ struct ptp_rtc_time {
struct ptp_time rtc_time;
};
+/* interface for PTP driver command SET_COMPENSATION */
+struct ptp_set_comp {
+ u32 drift;
+ bool o_ops;
+};
+
+/* interface for PTP driver command GET_ORIG_COMP */
+struct ptp_get_comp {
+ /* the initial compensation value */
+ u32 dw_origcomp;
+ /* the minimum compensation value */
+ u32 dw_mincomp;
+ /*the max compensation value*/
+ u32 dw_maxcomp;
+ /*the min drift applying min compensation value in ppm*/
+ u32 dw_mindrift;
+ /*the max drift applying max compensation value in ppm*/
+ u32 dw_maxdrift;
+};
+
+struct ptp_time_correct {
+ u32 corr_period;
+ u32 corr_inc;
+};
+
/* PTP message version */
#define PTP_1588_MSG_VER_1 1
#define PTP_1588_MSG_VER_2 2
@@ -124,7 +157,7 @@ struct fec_ptp_private {
};
#ifdef CONFIG_FEC_1588
-extern int fec_ptp_init(struct fec_ptp_private *priv);
+extern int fec_ptp_init(struct fec_ptp_private *priv, int id);
extern void fec_ptp_cleanup(struct fec_ptp_private *priv);
extern int fec_ptp_start(struct fec_ptp_private *priv);
extern void fec_ptp_stop(struct fec_ptp_private *priv);
@@ -134,7 +167,7 @@ extern void fec_ptp_store_rxstamp(struct fec_ptp_private *priv,
struct sk_buff *skb,
struct bufdesc *bdp);
#else
-static inline int fec_ptp_init(struct fec_ptp_private *priv)
+static inline int fec_ptp_init(struct fec_ptp_private *priv, int id)
{
return 1;
}
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index bd4e8d72dc08..e17b70291bbc 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -264,6 +264,8 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv)
(phydev->phy_id & phydrv->phy_id_mask));
}
+#ifdef CONFIG_PM
+
static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
{
struct device_driver *drv = phydev->dev.driver;
@@ -295,34 +297,88 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
return true;
}
-/* Suspend and resume. Copied from platform_suspend and
- * platform_resume
- */
-static int mdio_bus_suspend(struct device * dev, pm_message_t state)
+static int mdio_bus_suspend(struct device *dev)
{
struct phy_driver *phydrv = to_phy_driver(dev->driver);
struct phy_device *phydev = to_phy_device(dev);
+ /*
+ * We must stop the state machine manually, otherwise it stops out of
+ * control, possibly with the phydev->lock held. Upon resume, netdev
+ * may call phy routines that try to grab the same lock, and that may
+ * lead to a deadlock.
+ */
+ if (phydev->attached_dev)
+ phy_stop_machine(phydev);
+
if (!mdio_bus_phy_may_suspend(phydev))
return 0;
+
return phydrv->suspend(phydev);
}
-static int mdio_bus_resume(struct device * dev)
+static int mdio_bus_resume(struct device *dev)
{
struct phy_driver *phydrv = to_phy_driver(dev->driver);
struct phy_device *phydev = to_phy_device(dev);
+ int ret;
if (!mdio_bus_phy_may_suspend(phydev))
+ goto no_resume;
+
+ ret = phydrv->resume(phydev);
+ if (ret < 0)
+ return ret;
+
+no_resume:
+ if (phydev->attached_dev)
+ phy_start_machine(phydev, NULL);
+
+ return 0;
+}
+
+static int mdio_bus_restore(struct device *dev)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+ struct net_device *netdev = phydev->attached_dev;
+ int ret;
+
+ if (!netdev)
return 0;
- return phydrv->resume(phydev);
+
+ ret = phy_init_hw(phydev);
+ if (ret < 0)
+ return ret;
+
+ /* The PHY needs to renegotiate. */
+ phydev->link = 0;
+ phydev->state = PHY_UP;
+
+ phy_start_machine(phydev, NULL);
+
+ return 0;
}
+static struct dev_pm_ops mdio_bus_pm_ops = {
+ .suspend = mdio_bus_suspend,
+ .resume = mdio_bus_resume,
+ .freeze = mdio_bus_suspend,
+ .thaw = mdio_bus_resume,
+ .restore = mdio_bus_restore,
+};
+
+#define MDIO_BUS_PM_OPS (&mdio_bus_pm_ops)
+
+#else
+
+#define MDIO_BUS_PM_OPS NULL
+
+#endif /* CONFIG_PM */
+
struct bus_type mdio_bus_type = {
.name = "mdio_bus",
.match = mdio_bus_match,
- .suspend = mdio_bus_suspend,
- .resume = mdio_bus_resume,
+ .pm = MDIO_BUS_PM_OPS,
};
EXPORT_SYMBOL(mdio_bus_type);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index eda94fcd4065..d2df6382e123 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -413,7 +413,6 @@ EXPORT_SYMBOL(phy_start_aneg);
static void phy_change(struct work_struct *work);
-static void phy_state_machine(struct work_struct *work);
/**
* phy_start_machine - start PHY state machine tracking
@@ -433,7 +432,6 @@ void phy_start_machine(struct phy_device *phydev,
{
phydev->adjust_state = handler;
- INIT_DELAYED_WORK(&phydev->state_queue, phy_state_machine);
schedule_delayed_work(&phydev->state_queue, HZ);
}
@@ -764,7 +762,7 @@ EXPORT_SYMBOL(phy_start);
* phy_state_machine - Handle the state machine
* @work: work_struct that describes the work to be done
*/
-static void phy_state_machine(struct work_struct *work)
+void phy_state_machine(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct phy_device *phydev =
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index b10fedd82143..adbc0fded130 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -177,6 +177,7 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
dev->state = PHY_DOWN;
mutex_init(&dev->lock);
+ INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
return dev;
}
@@ -378,6 +379,20 @@ void phy_disconnect(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_disconnect);
+int phy_init_hw(struct phy_device *phydev)
+{
+ int ret;
+
+ if (!phydev->drv || !phydev->drv->config_init)
+ return 0;
+
+ ret = phy_scan_fixups(phydev);
+ if (ret < 0)
+ return ret;
+
+ return phydev->drv->config_init(phydev);
+}
+
/**
* phy_attach_direct - attach a network device to a given PHY device pointer
* @dev: network device to attach
@@ -425,21 +440,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
/* Do initial configuration here, now that
* we have certain key parameters
* (dev_flags and interface) */
- if (phydev->drv->config_init) {
- int err;
-
- err = phy_scan_fixups(phydev);
-
- if (err < 0)
- return err;
-
- err = phydev->drv->config_init(phydev);
-
- if (err < 0)
- return err;
- }
-
- return 0;
+ return phy_init_hw(phydev);
}
EXPORT_SYMBOL(phy_attach_direct);
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index d4c82f5fa555..a13d107a412b 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -789,6 +789,7 @@ static void smsc911x_phy_adjust_link(struct net_device *dev)
}
pdata->last_carrier = carrier;
}
+ udelay(10);
}
static int smsc911x_mii_probe(struct net_device *dev)
@@ -1011,7 +1012,7 @@ static int smsc911x_poll(struct napi_struct *napi, int budget)
struct net_device *dev = pdata->dev;
int npackets = 0;
- while (likely(netif_running(dev)) && (npackets < budget)) {
+ while (npackets < budget) {
unsigned int pktlength;
unsigned int pktwords;
struct sk_buff *skb;
@@ -1584,7 +1585,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id)
if (unlikely(intsts & inten & INT_STS_PHY_INT_)) {
smsc911x_reg_write( pdata, INT_STS , INT_STS_PHY_INT_);
temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, MII_INTSTS);
- SMSC_TRACE("PHY interrupt, sts 0x%04X", (u16)temp);
+ SMSC_TRACE(DRV,"PHY interrupt, sts 0x%04X", (u16)temp);
smsc911x_phy_adjust_link(dev);
serviced = IRQ_HANDLED;
}
diff --git a/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c b/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c
index 1ca77e513493..9d0c3773d4d7 100644
--- a/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c
+++ b/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c
@@ -56,7 +56,7 @@ ATH_DEBUG_INSTANTIATE_MODULE_VAR(android,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-char fwpath[256] = "/system/wifi";
+char fwpath[256] = "/lib/firmware/ath6k/AR6102";
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */
int buspm = WLAN_PWR_CTRL_CUT_PWR;
int wow2mode = WLAN_PWR_CTRL_CUT_PWR;
diff --git a/drivers/power/mxs/Makefile b/drivers/power/mxs/Makefile
index 6662defd9c70..c7675a9ec52b 100644
--- a/drivers/power/mxs/Makefile
+++ b/drivers/power/mxs/Makefile
@@ -5,5 +5,5 @@
obj-$(CONFIG_BATTERY_MXS) += mxs-battery.o
mxs-battery-objs := ddi_bc_api.o ddi_bc_hw.o ddi_bc_init.o \
- ddi_bc_ramp.o ddi_bc_sm.o ddi_power_battery.o linux.o
+ ddi_bc_ramp.o ddi_bc_sm.o ddi_power_battery.o linux.o fiq.o
diff --git a/drivers/power/mxs/ddi_bc_internal.h b/drivers/power/mxs/ddi_bc_internal.h
index a8510d08935c..b5bceeffae98 100644
--- a/drivers/power/mxs/ddi_bc_internal.h
+++ b/drivers/power/mxs/ddi_bc_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
*/
/*
@@ -41,6 +41,7 @@
/* Externs */
+#include <linux/kernel.h>
extern bool g_ddi_bc_Configured;
extern ddi_bc_Cfg_t g_ddi_bc_Configuration;
diff --git a/drivers/power/mxs/ddi_power_battery.c b/drivers/power/mxs/ddi_power_battery.c
index 6e2119af1676..762f29bd784e 100644
--- a/drivers/power/mxs/ddi_power_battery.c
+++ b/drivers/power/mxs/ddi_power_battery.c
@@ -1805,9 +1805,11 @@ void ddi_power_enable_vddio_interrupt(bool enable)
}
+
void ddi_power_handle_vddio_brnout(void)
{
- if (ddi_power_GetPmu5vStatus() == new_5v_connection) {
+ if (ddi_power_GetPmu5vStatus() == new_5v_connection ||
+ (ddi_power_GetPmu5vStatus() == new_5v_disconnection)) {
ddi_power_enable_vddio_interrupt(false);
} else {
#ifdef DEBUG_IRQS
diff --git a/drivers/power/mxs/fiq.S b/drivers/power/mxs/fiq.S
index ee71730c85c9..1ad380d07efd 100644
--- a/drivers/power/mxs/fiq.S
+++ b/drivers/power/mxs/fiq.S
@@ -19,11 +19,10 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
-#include <mach/platform.h>
#include <mach/hardware.h>
#include <asm/pgtable-hwdef.h>
#include <mach/regs-power.h>
-#include <mach/regs-clkctrl.h>
+#include <mach/../../regs-clkctrl.h>
#include <mach/regs-timrot.h>
.align 5
@@ -33,7 +32,6 @@
.globl lock_vector_tlb
power_fiq_start:
-
ldr r8,power_reg
ldr r9,[r8,#HW_POWER_CTRL ]
ldr r10,power_off
@@ -101,7 +99,7 @@ check_dcdc4p2:
subs pc,lr, #4
power_reg:
- .long REGS_POWER_BASE
+ .long IO_ADDRESS(POWER_PHYS_ADDR)
power_off:
.long 0x3e770001
power_bo:
diff --git a/drivers/power/mxs/linux.c b/drivers/power/mxs/linux.c
index 6a3172415145..1c2dfc10f7ca 100644
--- a/drivers/power/mxs/linux.c
+++ b/drivers/power/mxs/linux.c
@@ -102,7 +102,7 @@ struct mxs_info {
#define IRQ_DCDC4P2_BRNOUT IRQ_DCDC4P2_BO
#endif
-/* #define POWER_FIQ */
+#define POWER_FIQ
/* #define DEBUG_IRQS */
@@ -129,9 +129,7 @@ void init_protection(struct mxs_info *info)
battery_voltage = ddi_power_GetBattery();
/* InitializeFiqSystem(); */
-#ifdef CONFIG_ARCH_MX23
ddi_power_InitOutputBrownouts();
-#endif
/* if we start the kernel with 4p2 already started
@@ -238,12 +236,12 @@ static void check_and_handle_5v_connection(struct mxs_info *info)
*/
if ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL)
& BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) ==
- (0x8 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT)) {
+ (0x20 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT)) {
dev_info(info->dev, "waiting USB enum done...\r\n");
}
while ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL)
& BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT)
- == (0x8 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT)) {
+ == (0x20 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT)) {
msleep(50);
}
#endif
@@ -299,7 +297,7 @@ static void check_and_handle_5v_connection(struct mxs_info *info)
__raw_writel(__raw_readl(REGS_POWER_BASE +
HW_POWER_5VCTRL) &
(~BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT)
- | (0x8 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT),
+ | (0x20 << BP_POWER_5VCTRL_CHARGE_4P2_ILIMIT),
REGS_POWER_BASE + HW_POWER_5VCTRL);
}
@@ -659,6 +657,8 @@ static irqreturn_t mxs_irq_batt_brnout(int irq, void *cookie)
#endif
return IRQ_HANDLED;
}
+
+
static irqreturn_t mxs_irq_vddd_brnout(int irq, void *cookie)
{
#ifdef DEBUG_IRQS
@@ -1144,13 +1144,13 @@ static int __init mxs_bat_init(void)
#ifdef CONFIG_MXS_VBUS_CURRENT_DRAW
if (((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) &
- BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x8000)
+ BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x20000)
&& ((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) &
BM_POWER_5VCTRL_PWD_CHARGE_4P2) == 0)) {
#ifdef CONFIG_USB_GADGET
printk(KERN_INFO "USB GADGET exist,wait USB enum done...\r\n");
while (((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL)
- & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x8000) &&
+ & BM_POWER_5VCTRL_CHARGE_4P2_ILIMIT) == 0x20000) &&
((__raw_readl(REGS_POWER_BASE + HW_POWER_5VCTRL) &
BM_POWER_5VCTRL_PWD_CHARGE_4P2) == 0))
;
@@ -1161,8 +1161,7 @@ static int __init mxs_bat_init(void)
}
cpu = clk_get(NULL, "cpu");
pll0 = clk_get(NULL, "ref_cpu");
- if (cpu->set_parent)
- cpu->set_parent(cpu, pll0);
+ clk_set_parent(cpu, pll0);
#endif
return platform_driver_register(&mxs_batdrv);
}
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index fd3183e30a1c..804c32cabb50 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -153,4 +153,9 @@ config REGULATOR_MC9S08DZ60
depends on MXC_PMIC_MC9S08DZ60
default y
+config REGULATOR_MAX17135
+ tristate "Maxim MAX17135 Regulator Support"
+ depends on REGULATOR
+ default n
+
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index a10178d99acc..d88116ba8139 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
+obj-$(CONFIG_REGULATOR_MAX17135) += max17135-regulator.o
obj-$(CONFIG_REGULATOR_MC13892) += reg-mc13892.o
obj-$(CONFIG_REGULATOR_MC13783) += reg-mc13783.o
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 09492700cddf..bd320c1ab70c 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -109,6 +109,16 @@ config RTC_INTF_DEV_UIE_EMUL
clock several times per second, please enable this option
only if you know that you really need it.
+config RTC_INTF_ALARM
+ bool "Android alarm driver"
+ depends on RTC_CLASS
+ default y
+ help
+ Provides non-wakeup and rtc backed wakeup alarms based on rtc or
+ elapsed realtime, and a non-wakeup alarm on the monotonic clock.
+ Also provides an ioctl to set the wall time which must be used
+ for elapsed realtime to work.
+
config RTC_DRV_TEST
tristate "Test driver/device"
help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 91da97eca589..c8df86258348 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o
obj-$(CONFIG_RTC_CLASS) += rtc-core.o
rtc-core-y := class.o interface.o
+rtc-core-$(CONFIG_RTC_INTF_ALARM) += alarm.o
rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
index 5d410fd9d5d2..beb31415a4da 100644
--- a/drivers/rtc/rtc-mxc_v2.c
+++ b/drivers/rtc/rtc-mxc_v2.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -37,6 +37,10 @@
#include <linux/uaccess.h>
#include <mach/hardware.h>
#include <asm/io.h>
+#include <linux/mxc_srtc.h>
+
+
+#define SRTC_LPSCLR_LLPSC_LSH 17 /* start bit for LSB time value */
#define SRTC_LPPDR_INIT 0x41736166 /* init for glitch detect */
@@ -147,6 +151,12 @@ struct rtc_drv_data {
bool irq_enable;
};
+
+/* completion event for implementing RTC_WAIT_FOR_TIME_SET ioctl */
+DECLARE_COMPLETION(srtc_completion);
+/* global to save difference of 47-bit counter value */
+static int64_t time_diff;
+
/*!
* @defgroup RTC Real Time Clock (RTC) Driver
*/
@@ -313,6 +323,8 @@ static int mxc_rtc_ioctl(struct device *dev, unsigned int cmd,
void __iomem *ioaddr = pdata->ioaddr;
unsigned long lock_flags = 0;
u32 lp_cr;
+ u64 time_47bit;
+ int retVal;
switch (cmd) {
case RTC_AIE_OFF:
@@ -339,6 +351,36 @@ static int mxc_rtc_ioctl(struct device *dev, unsigned int cmd,
__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
spin_unlock_irqrestore(&rtc_lock, lock_flags);
return 0;
+
+ case RTC_READ_TIME_47BIT:
+ time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 |
+ ((u64) __raw_readl(ioaddr + SRTC_LPSCLR)));
+ time_47bit >>= SRTC_LPSCLR_LLPSC_LSH;
+
+ if (arg && copy_to_user((u64 *) arg, &time_47bit, sizeof(u64)))
+ return -EFAULT;
+
+ return 0;
+
+ case RTC_WAIT_TIME_SET:
+
+ /* don't block without releasing mutex first */
+ mutex_unlock(&pdata->rtc->ops_lock);
+
+ /* sleep until awakened by SRTC driver when LPSCMR is changed */
+ wait_for_completion(&srtc_completion);
+
+ /* relock mutex because rtc_dev_ioctl will unlock again */
+ retVal = mutex_lock_interruptible(&pdata->rtc->ops_lock);
+
+ /* copy the new time difference = new time - previous time
+ * to the user param. The difference is a signed value */
+ if (arg && copy_to_user((int64_t *) arg, &time_diff,
+ sizeof(int64_t)))
+ return -EFAULT;
+
+ return retVal;
+
}
return -ENOIOCTLCMD;
@@ -372,14 +414,31 @@ static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
struct rtc_drv_data *pdata = dev_get_drvdata(dev);
void __iomem *ioaddr = pdata->ioaddr;
unsigned long time;
+ u64 old_time_47bit, new_time_47bit;
int ret;
ret = rtc_tm_to_time(tm, &time);
if (ret != 0)
return ret;
+ old_time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 |
+ ((u64) __raw_readl(ioaddr + SRTC_LPSCLR)));
+ old_time_47bit >>= SRTC_LPSCLR_LLPSC_LSH;
+
__raw_writel(time, ioaddr + SRTC_LPSCMR);
rtc_write_sync_lp(ioaddr);
+ new_time_47bit = (((u64) __raw_readl(ioaddr + SRTC_LPSCMR)) << 32 |
+ ((u64) __raw_readl(ioaddr + SRTC_LPSCLR)));
+ new_time_47bit >>= SRTC_LPSCLR_LLPSC_LSH;
+
+ /* update the difference between previous time and new time */
+ time_diff = new_time_47bit - old_time_47bit;
+
+ /* signal all waiting threads that time changed */
+ complete_all(&srtc_completion);
+ /* reinitialize completion variable */
+ INIT_COMPLETION(srtc_completion);
+
return 0;
}
@@ -549,41 +608,30 @@ static int mxc_rtc_probe(struct platform_device *pdev)
/* clear lp interrupt status */
__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
- udelay(100);;
+ udelay(100);
plat_data = (struct mxc_srtc_platform_data *)pdev->dev.platform_data;
- clk = clk_get(NULL, "iim_clk");
- clk_enable(clk);
- srtc_secmode_addr = ioremap(plat_data->srtc_sec_mode_addr, 1);
-
- /* Check SRTC security mode */
- if (((__raw_readl(srtc_secmode_addr) & SRTC_SECMODE_MASK) ==
- SRTC_SECMODE_LOW) && (cpu_is_mx51_rev(CHIP_REV_1_0) == 1)) {
- /* Workaround for MX51 TO1 due to inaccurate CKIL clock */
- __raw_writel(SRTC_LPCR_EN_LP, ioaddr + SRTC_LPCR);
- udelay(100);
- } else {
- /* move out of init state */
- __raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA),
- ioaddr + SRTC_LPCR);
- udelay(100);
+ /* move out of init state */
+ __raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA),
+ ioaddr + SRTC_LPCR);
- while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0);
+ udelay(100);
- /* move out of non-valid state */
- __raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
- SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
+ while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
+ ;
- udelay(100);
+ /* move out of non-valid state */
+ __raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
+ SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
- while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0);
+ udelay(100);
- __raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
- udelay(100);
- }
- clk_disable(clk);
- clk_put(clk);
+ while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
+ ;
+
+ __raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
+ udelay(100);
rtc = rtc_device_register(pdev->name, &pdev->dev,
&mxc_rtc_ops, THIS_MODULE);
diff --git a/drivers/rtc/rtc-mxs.c b/drivers/rtc/rtc-mxs.c
index 0e2b0e1e14f6..bb4c33b1a0ba 100644
--- a/drivers/rtc/rtc-mxs.c
+++ b/drivers/rtc/rtc-mxs.c
@@ -254,6 +254,8 @@ static int mxs_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rtc_data);
+ device_init_wakeup(&pdev->dev, 1);
+
return 0;
}
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 869337a7fd68..b41db4d22436 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -373,6 +373,24 @@ config SERIAL_MXS_AUART
help
Driver for Freescale i.MXS internal application serial port
+config SERIAL_MXS_AUART_CONSOLE
+ bool "Support for console on i.MXS application serial port"
+ depends on SERIAL_MXS_AUART=y
+ select SERIAL_CORE_CONSOLE
+ ---help---
+ Say Y here if you wish to use the i.MXS app serial port as the
+ system console (the system console is the device which receives all
+ kernel messages and warnings and which allows logins in single user
+ mode).
+
+ Even if you say Y here, the currently visible framebuffer console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttySP1". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
+
config SERIAL_MXS_DUART_CONSOLE
bool "Support for console on i.MXS debug serial port"
depends on SERIAL_MXS_DUART=y
diff --git a/drivers/serial/mxs-auart.c b/drivers/serial/mxs-auart.c
index 0eea46d71979..63d7d9128efc 100644
--- a/drivers/serial/mxs-auart.c
+++ b/drivers/serial/mxs-auart.c
@@ -19,6 +19,7 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/console.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -47,6 +48,8 @@
#define MXS_AUART_MAJOR 242
#define MXS_AUART_RX_THRESHOLD 16
+static struct uart_driver auart_driver;
+
struct mxs_auart_port {
struct uart_port port;
@@ -514,7 +517,7 @@ static void mxs_auart_settermios(struct uart_port *u,
/* parity */
if (cflag & PARENB) {
- ctrl |= BM_UARTAPP_LINECTRL_PEN | BM_UARTAPP_LINECTRL_SPS;
+ ctrl |= BM_UARTAPP_LINECTRL_PEN;
if ((cflag & PARODD) == 0)
ctrl |= BM_UARTAPP_LINECTRL_EPS;
}
@@ -565,9 +568,33 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
mxs_auart_tx_chars(s);
istat &= ~BM_UARTAPP_INTR_TXIS;
}
- if (istat & 0xFFFF)
+ /* modem status interrupt bits are undefined
+ after reset,and the hardware do not support
+ DSRMIS,DCDMIS and RIMIS bit,so we should ingore
+ them when they are pending. */
+ if (istat & (BM_UARTAPP_INTR_ABDIS
+ | BM_UARTAPP_INTR_OEIS
+ | BM_UARTAPP_INTR_BEIS
+ | BM_UARTAPP_INTR_PEIS
+ | BM_UARTAPP_INTR_FEIS
+ | BM_UARTAPP_INTR_RTIS
+ | BM_UARTAPP_INTR_TXIS
+ | BM_UARTAPP_INTR_RXIS
+ | BM_UARTAPP_INTR_CTSMIS)) {
dev_info(s->dev, "Unhandled status %x\n", istat);
- __raw_writel(istatus & 0xFFFF,
+ }
+ __raw_writel(istatus & (BM_UARTAPP_INTR_ABDIS
+ | BM_UARTAPP_INTR_OEIS
+ | BM_UARTAPP_INTR_BEIS
+ | BM_UARTAPP_INTR_PEIS
+ | BM_UARTAPP_INTR_FEIS
+ | BM_UARTAPP_INTR_RTIS
+ | BM_UARTAPP_INTR_TXIS
+ | BM_UARTAPP_INTR_RXIS
+ | BM_UARTAPP_INTR_DSRMIS
+ | BM_UARTAPP_INTR_DCDMIS
+ | BM_UARTAPP_INTR_CTSMIS
+ | BM_UARTAPP_INTR_RIMIS),
s->port.membase + HW_UARTAPP_INTR_CLR);
return IRQ_HANDLED;
@@ -761,7 +788,160 @@ static struct uart_ops mxs_auart_ops = {
.config_port = mxs_auart_config_port,
.verify_port = mxs_auart_verify_port,
};
+#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
+static struct mxs_auart_port auart_port[CONFIG_MXS_AUART_PORTS] = {};
+
+static void
+auart_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct uart_port *port;
+ unsigned int status, old_cr;
+ int i;
+
+ if (co->index > CONFIG_MXS_AUART_PORTS || co->index < 0)
+ return;
+
+ port = &auart_port[co->index].port;
+
+ /* First save the CR then disable the interrupts */
+ old_cr = __raw_readl(port->membase + HW_UARTAPP_CTRL2);
+ __raw_writel(BM_UARTAPP_CTRL2_UARTEN | BM_UARTAPP_CTRL2_TXE,
+ port->membase + HW_UARTAPP_CTRL2_SET);
+
+ /* Now, do each character */
+ for (i = 0; i < count; i++) {
+ do {
+ status = __raw_readl(port->membase + HW_UARTAPP_STAT);
+ } while (status & BM_UARTAPP_STAT_TXFF);
+
+ __raw_writel(s[i], port->membase + HW_UARTAPP_DATA);
+ if (s[i] == '\n') {
+ do {
+ status = __raw_readl(port->membase +
+ HW_UARTAPP_STAT);
+ } while (status & BM_UARTAPP_STAT_TXFF);
+ __raw_writel('\r', port->membase + HW_UARTAPP_DATA);
+ }
+ }
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the TCR
+ */
+ do {
+ status = __raw_readl(port->membase + HW_UARTAPP_STAT);
+ } while (status & BM_UARTAPP_STAT_BUSY);
+ __raw_writel(old_cr, port->membase + HW_UARTAPP_CTRL2);
+}
+
+static void __init
+auart_console_get_options(struct uart_port *port, int *baud,
+ int *parity, int *bits)
+{
+ if (__raw_readl(port->membase + HW_UARTAPP_CTRL2)
+ & BM_UARTAPP_CTRL2_UARTEN) {
+ unsigned int lcr_h, quot;
+ lcr_h = __raw_readl(port->membase + HW_UARTAPP_LINECTRL);
+
+ *parity = 'n';
+ if (lcr_h & BM_UARTAPP_LINECTRL_PEN) {
+ if (lcr_h & BM_UARTAPP_LINECTRL_EPS)
+ *parity = 'e';
+ else
+ *parity = 'o';
+ }
+
+ if ((lcr_h & BM_UARTAPP_LINECTRL_WLEN)
+ == BF_UARTAPP_LINECTRL_WLEN(2))
+ *bits = 7;
+ else
+ *bits = 8;
+
+ quot = (((__raw_readl(port->membase + HW_UARTAPP_LINECTRL)
+ & BM_UARTAPP_LINECTRL_BAUD_DIVINT))
+ >> (BP_UARTAPP_LINECTRL_BAUD_DIVINT - 6))
+ | (((__raw_readl(port->membase + HW_UARTAPP_LINECTRL)
+ & BM_UARTAPP_LINECTRL_BAUD_DIVFRAC))
+ >> BP_UARTAPP_LINECTRL_BAUD_DIVFRAC);
+ if (quot == 0)
+ quot = 1;
+ *baud = (port->uartclk << 2) / quot;
+ }
+}
+
+static int __init auart_console_setup(struct console *co, char *options)
+{
+ struct mxs_auart_port *port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (co->index > CONFIG_MXS_AUART_PORTS || co->index < 0)
+ return -EINVAL;
+
+ port = &auart_port[co->index].port;
+
+ if (port->port.membase == 0) {
+ if (cpu_is_mx23()) {
+ if (co->index == 1) {
+ port->port.membase = IO_ADDRESS(0x8006C000);
+ port->port.mapbase = 0x8006C000;
+ } else {
+ port->port.membase = IO_ADDRESS(0x8006E000);
+ port->port.mapbase = 0x8006E000;
+ }
+ }
+
+ port->port.fifosize = 16;
+ port->port.ops = &mxs_auart_ops;
+ port->port.flags = ASYNC_BOOT_AUTOCONF;
+ port->port.line = 0;
+ }
+ mxs_auart_reset(port);
+
+ __raw_writel(BM_UARTAPP_CTRL2_UARTEN,
+ port->port.membase + HW_UARTAPP_CTRL2_SET);
+
+ if (port->clk == NULL || IS_ERR(port->clk)) {
+ port->clk = clk_get(NULL, "uart");
+ if (port->clk == NULL || IS_ERR(port->clk))
+ return -ENODEV;
+ port->port.uartclk = clk_get_rate(port->clk);
+ }
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ auart_console_get_options(port, &baud, &parity, &bits);
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console auart_console = {
+ .name = "ttySP",
+ .write = auart_console_write,
+ .device = uart_console_device,
+ .setup = auart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &auart_driver,
+};
+#ifdef CONFIG_MXS_EARLY_CONSOLE
+static int __init auart_console_init(void)
+{
+ register_console(&auart_console);
+ return 0;
+}
+
+console_initcall(auart_console_init);
+#endif
+
+#endif
static struct uart_driver auart_driver = {
.owner = THIS_MODULE,
.driver_name = "auart",
@@ -769,6 +949,9 @@ static struct uart_driver auart_driver = {
.major = MXS_AUART_MAJOR,
.minor = 0,
.nr = CONFIG_MXS_AUART_PORTS,
+#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
+ .cons = &auart_console,
+#endif
};
static int __devinit mxs_auart_probe(struct platform_device *pdev)
@@ -849,6 +1032,10 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
+#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
+ memcpy(&auart_port[pdev->id], s, sizeof(struct mxs_auart_port));
+#endif
+
ret = uart_add_one_port(&auart_driver, &s->port);
if (ret)
goto out_free_clk;
diff --git a/drivers/serial/mxs-duart.c b/drivers/serial/mxs-duart.c
index 5d006f380930..171b8628faee 100644
--- a/drivers/serial/mxs-duart.c
+++ b/drivers/serial/mxs-duart.c
@@ -735,9 +735,40 @@ static int __devexit duart_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int duart_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ int ret = 0;
+ if (!duart_port.suspended) {
+ ret = uart_suspend_port(&duart_drv, &duart_port.port);
+ if (!ret)
+ duart_port.suspended = 1;
+ }
+ return ret;
+}
+
+static int duart_resume(struct platform_device *pdev,
+ pm_message_t state)
+{
+ int ret = 0;
+ if (duart_port.suspended) {
+ ret = uart_resume_port(&duart_drv, &duart_port.port);
+ if (!ret)
+ duart_port.suspended = 0;
+ }
+ return ret;
+}
+#else
+#define duart_suspend NULL
+#define duart_resume NULL
+#endif
+
static struct platform_driver duart_driver = {
.probe = duart_probe,
.remove = __devexit_p(duart_remove),
+ .suspend = duart_suspend,
+ .resume = duart_resume,
.driver = {
.name = "mxs-duart",
.owner = THIS_MODULE,
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index e16915107c6b..736a12ff9045 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -261,6 +261,11 @@ config SPI_STMP3XXX
help
SPI driver for Freescale STMP37xx/378x SoC SSP interface
+config SPI_MXS
+ tristate "Freescale MXS SPI/SSP controller"
+ depends on ARCH_MXS && SPI_MASTER
+ help
+ SPI driver for Freescale MXS SoC SSP interface
#
# Add new SPI master controllers in alphabetical order above this line
#
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index b7cfb6245c0b..b6dbdf064181 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_SPI_MXC) += mxc_spi.o
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o
obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
+obj-$(CONFIG_SPI_MXS) += spi_mxs.o
# ... add above this line ...
# SPI protocol drivers (device/link on bus)
diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c
index cfe40a4526a7..5f4aa2e90392 100644
--- a/drivers/spi/mxc_spi.c
+++ b/drivers/spi/mxc_spi.c
@@ -657,7 +657,7 @@ void mxc_spi_chipselect(struct spi_device *spi, int is_active)
if (spi->mode & SPI_CPHA)
ctrl_reg |=
spi_ver_def->mode_mask << spi_ver_def->pha_shift;
- if (!(spi->mode & SPI_CPOL))
+ if (spi->mode & SPI_CPOL)
ctrl_reg |=
spi_ver_def->mode_mask << spi_ver_def->
low_pol_shift;
@@ -824,16 +824,23 @@ int mxc_spi_poll_transfer(struct spi_device *spi, struct spi_transfer *t)
master_drv_data->transfer.count = t->len;
fifo_size = master_drv_data->spi_ver_def->fifo_size;
- count = (t->len > fifo_size) ? fifo_size : t->len;
- spi_put_tx_data(master_drv_data->base, count, master_drv_data);
+ while (master_drv_data->transfer.count) {
+ count = (master_drv_data->transfer.count > fifo_size) ?
+ fifo_size : master_drv_data->transfer.count;
- while ((((status = __raw_readl(master_drv_data->test_addr)) &
- master_drv_data->spi_ver_def->rx_cnt_mask) >> master_drv_data->
- spi_ver_def->rx_cnt_off) != count);
+ spi_put_tx_data(master_drv_data->base, count, master_drv_data);
- for (i = 0; i < count; i++) {
- rx_tmp = __raw_readl(master_drv_data->base + MXC_CSPIRXDATA);
- master_drv_data->transfer.rx_get(master_drv_data, rx_tmp);
+ while ((((status = __raw_readl(master_drv_data->test_addr)) &
+ master_drv_data->spi_ver_def->rx_cnt_mask) >> master_drv_data->
+ spi_ver_def->rx_cnt_off) != count)
+ ;
+
+ for (i = 0; i < count; i++) {
+ rx_tmp = __raw_readl(master_drv_data->base + MXC_CSPIRXDATA);
+ master_drv_data->transfer.rx_get(master_drv_data, rx_tmp);
+ }
+
+ master_drv_data->transfer.count -= count;
}
clk_disable(master_drv_data->clk);
@@ -864,8 +871,19 @@ int mxc_spi_transfer(struct spi_device *spi, struct spi_transfer *t)
int chipselect_status;
u32 fifo_size;
+#if defined(CONFIG_MODULE_CCXMX51)
+ /**
+ * The ConnectCore i.MX51/Wi-i.MX51 use this bus to communicate with
+ * the pmic, using poll transfers. Because that bus is also used to
+ * communicate the cpu with other devices, use also poll transfers
+ * to avoid conflicts.
+ */
+ if (spi->master->bus_num == 1) {
+ mxc_spi_poll_transfer(spi, t);
+ return t->len;
+ }
+#endif
/* Get the master controller driver data from spi device's master */
-
master_drv_data = spi_master_get_devdata(spi->master);
chipselect_status = __raw_readl(MXC_CSPICONFIG +
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 17d89a8124ad..da7c984b5641 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -43,6 +43,7 @@ static struct proc_dir_entry *binder_proc_dir_entry_proc;
static struct hlist_head binder_dead_nodes;
static HLIST_HEAD(binder_deferred_list);
static DEFINE_MUTEX(binder_deferred_lock);
+static struct workqueue_struct *binder_deferred_workqueue;
static int binder_read_proc_proc(char *page, char **start, off_t off,
int count, int *eof, void *data);
@@ -2986,6 +2987,7 @@ static void binder_deferred_release(struct binder_proc *proc)
int i;
for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) {
if (proc->pages[i]) {
+ void *page_addr = proc->buffer + i * PAGE_SIZE;
if (binder_debug_mask &
BINDER_DEBUG_BUFFER_ALLOC)
printk(KERN_INFO
@@ -2993,6 +2995,8 @@ static void binder_deferred_release(struct binder_proc *proc)
"page %d at %p not freed\n",
proc->pid, i,
proc->buffer + i * PAGE_SIZE);
+ unmap_kernel_range((unsigned long)page_addr,
+ PAGE_SIZE);
__free_page(proc->pages[i]);
page_count++;
}
@@ -3062,7 +3066,7 @@ static void binder_defer_work(struct binder_proc *proc, int defer)
if (hlist_unhashed(&proc->deferred_work_node)) {
hlist_add_head(&proc->deferred_work_node,
&binder_deferred_list);
- schedule_work(&binder_deferred_work);
+ queue_work(binder_deferred_workqueue, &binder_deferred_work);
}
mutex_unlock(&binder_deferred_lock);
}
@@ -3690,6 +3694,10 @@ static int __init binder_init(void)
{
int ret;
+ binder_deferred_workqueue = create_singlethread_workqueue("binder");
+ if (!binder_deferred_workqueue)
+ return -ENOMEM;
+
binder_proc_dir_entry_root = proc_mkdir("binder", NULL);
if (binder_proc_dir_entry_root)
binder_proc_dir_entry_proc = proc_mkdir("proc",
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index 6c10b456c6cc..7f64f8fb26b0 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -556,6 +556,7 @@ static struct logger_log VAR = { \
DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024)
DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024)
DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024)
+DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 64*1024)
static struct logger_log *get_log_from_minor(int minor)
{
@@ -565,6 +566,8 @@ static struct logger_log *get_log_from_minor(int minor)
return &log_events;
if (log_radio.misc.minor == minor)
return &log_radio;
+ if (log_system.misc.minor == minor)
+ return &log_system;
return NULL;
}
@@ -601,6 +604,10 @@ static int __init logger_init(void)
if (unlikely(ret))
goto out;
+ ret = init_log(&log_system);
+ if (unlikely(ret))
+ goto out;
+
out:
return ret;
}
diff --git a/drivers/staging/android/logger.h b/drivers/staging/android/logger.h
index a562434d7419..2cb06e9d8f98 100644
--- a/drivers/staging/android/logger.h
+++ b/drivers/staging/android/logger.h
@@ -32,6 +32,7 @@ struct logger_entry {
#define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */
#define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */
+#define LOGGER_LOG_SYSTEM "log_system" /* system/framework messages */
#define LOGGER_LOG_MAIN "log_main" /* everything else */
#define LOGGER_ENTRY_MAX_LEN (4*1024)
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 803b891dc85e..572dc062759a 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -18,6 +18,9 @@
#include <linux/mm.h>
#include <linux/oom.h>
#include <linux/sched.h>
+#include <linux/nodemask.h>
+#include <linux/vmstat.h>
+#include <linux/notifier.h>
static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask);
@@ -41,6 +44,8 @@ static size_t lowmem_minfree[6] = {
};
static int lowmem_minfree_size = 4;
+static struct task_struct *lowmem_deathpending;
+
#define lowmem_print(level, x...) \
do { \
if (lowmem_debug_level >= (level)) \
@@ -54,6 +59,24 @@ module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size,
S_IRUGO | S_IWUSR);
module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR);
+static int
+task_notify_func(struct notifier_block *self, unsigned long val, void *data);
+
+static struct notifier_block task_nb = {
+ .notifier_call = task_notify_func,
+};
+
+static int
+task_notify_func(struct notifier_block *self, unsigned long val, void *data)
+{
+ struct task_struct *task = data;
+ if (task == lowmem_deathpending) {
+ lowmem_deathpending = NULL;
+ task_free_unregister(&task_nb);
+ }
+ return NOTIFY_OK;
+}
+
static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask)
{
struct task_struct *p;
@@ -67,6 +90,24 @@ static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask)
int array_size = ARRAY_SIZE(lowmem_adj);
int other_free = global_page_state(NR_FREE_PAGES);
int other_file = global_page_state(NR_FILE_PAGES);
+ int node;
+
+ /*
+ * If we already have a death outstanding, then
+ * bail out right away; indicating to vmscan
+ * that we have nothing further to offer on
+ * this pass.
+ */
+ if (lowmem_deathpending)
+ return 0;
+
+ for_each_node_state(node, N_HIGH_MEMORY) {
+ struct zone *z =
+ &NODE_DATA(node)->node_zones[ZONE_DMA];
+
+ other_free -= zone_page_state(z, NR_FREE_PAGES);
+ other_file -= zone_page_state(z, NR_FILE_PAGES);
+ }
if (lowmem_adj_size < array_size)
array_size = lowmem_adj_size;
@@ -128,9 +169,19 @@ static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask)
p->pid, p->comm, oom_adj, tasksize);
}
if (selected) {
+ if (fatal_signal_pending(selected)) {
+ pr_warning("process %d is suffering a slow death\n",
+ selected->pid);
+ read_unlock(&tasklist_lock);
+ return rem;
+ }
lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",
selected->pid, selected->comm,
selected_oom_adj, selected_tasksize);
+
+ lowmem_deathpending = selected;
+ task_free_register(&task_nb);
+
force_sig(SIGKILL, selected);
rem -= selected_tasksize;
}
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index 3f06818cf9fa..31fcd3270b26 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -157,6 +157,12 @@ static int uio_pdrv_genirq_remove(struct platform_device *pdev)
struct uio_pdrv_genirq_platdata *priv = platform_get_drvdata(pdev);
uio_unregister_device(priv->uioinfo);
+
+ priv->uioinfo->irq_flags = 0;
+ priv->uioinfo->handler = NULL;
+ priv->uioinfo->irqcontrol = NULL;
+ priv->uioinfo->priv = NULL;
+
kfree(priv);
return 0;
}
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 2bfc41ece0e1..b8134ad5f05f 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -59,6 +59,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
+#include <linux/serial.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
@@ -609,6 +610,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
acm->throttle = 0;
tasklet_schedule(&acm->urb_task);
+ set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
rv = tty_port_block_til_ready(&acm->port, tty, filp);
done:
mutex_unlock(&acm->mutex);
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 69e5773abfce..07f503aa9078 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1754,6 +1754,9 @@ int usb_resume(struct device *dev, pm_message_t msg)
udev = to_usb_device(dev);
+/* At otg mode, if it is a device wakeup interrupt, the host should do nothing */
+ if (udev->bus->is_b_host)
+ return 0;
/* If udev->skip_sys_resume is set then udev was already suspended
* when the system sleep started, so we don't want to resume it
* during this system wakeup.
@@ -1765,7 +1768,7 @@ int usb_resume(struct device *dev, pm_message_t msg)
/* Avoid PM error messages for devices disconnected while suspended
* as we'll display regular disconnect messages just a bit later.
*/
- if (status == -ENODEV)
+ if (status == -ENODEV || status == -ESHUTDOWN)
return 0;
return status;
}
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 66e8a424c9f4..539a2c0dde00 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -196,7 +196,6 @@ extern void usb_host_set_wakeup(struct device *wkup_dev, bool para);
static int generic_suspend(struct usb_device *udev, pm_message_t msg)
{
int rc;
- u32 temp;
/* Normal USB devices suspend through their upstream port.
* Root hubs don't have upstream ports to suspend,
@@ -204,25 +203,7 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
* interfaces manually by doing a bus (or "global") suspend.
*/
if (!udev->parent) {
- struct usb_hcd *hcd =
- container_of(udev->bus, struct usb_hcd, self);
- struct fsl_usb2_platform_data *pdata;
- pdata = hcd->self.controller->platform_data;
-
rc = hcd_bus_suspend(udev, msg);
-
- if (device_may_wakeup(hcd->self.controller)) {
- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- /* enable remote wake up irq */
- usb_host_set_wakeup(hcd->self.controller, true);
-
- /* Put PHY into low power mode */
- temp = readl(hcd->regs + 0x184);
- writel(temp | (1 << 23), (hcd->regs + 0x184));
-
- if (pdata->usb_clock_for_pm)
- pdata->usb_clock_for_pm(false);
- }
/* Non-root devices don't need to do anything for FREEZE or PRETHAW */
} else if (msg.event == PM_EVENT_FREEZE ||
msg.event == PM_EVENT_PRETHAW)
@@ -236,7 +217,6 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
static int generic_resume(struct usb_device *udev, pm_message_t msg)
{
int rc;
- u32 temp;
/* Normal USB devices resume/reset through their upstream port.
* Root hubs don't have upstream ports to resume or reset,
@@ -244,13 +224,6 @@ static int generic_resume(struct usb_device *udev, pm_message_t msg)
* interfaces manually by doing a bus (or "global") resume.
*/
if (!udev->parent) {
- struct usb_hcd *hcd =
- container_of(udev->bus, struct usb_hcd, self);
-
- if (device_may_wakeup(hcd->self.controller)) {
- temp = readl(hcd->regs + 0x184);
- writel(temp & (~(1 << 23)), (hcd->regs + 0x184));
- }
rc = hcd_bus_resume(udev, msg);
} else
rc = usb_port_resume(udev, msg);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index d27ad104731c..2f47bdc7c93a 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1739,6 +1739,7 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
int status;
int old_state = hcd->state;
+ printk("%s\n", __func__);
dev_dbg(&rhdev->dev, "bus %s%s\n",
(msg.event & PM_EVENT_AUTO ? "auto-" : ""), "suspend");
if (!hcd->driver->bus_suspend) {
@@ -1876,7 +1877,6 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);
irqreturn_t usb_hcd_irq (int irq, void *__hcd)
{
struct usb_hcd *hcd = __hcd;
- struct fsl_usb2_platform_data *pdata;
unsigned long flags;
irqreturn_t rc;
@@ -1885,25 +1885,14 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
* assume it's never used.
*/
local_irq_save(flags);
-
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
- /* Need open clock for register access */
- pdata = hcd->self.controller->platform_data;
- if (pdata->usb_clock_for_pm)
- pdata->usb_clock_for_pm(true);
-
- /* if receive a remote wakeup interrrupt after suspend */
- if (usb_host_wakeup_irq(hcd->self.controller)) {
- /* disable remote wake up irq */
- usb_host_set_wakeup(hcd->self.controller, false);
-
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- hcd->driver->irq(hcd);
- rc = IRQ_HANDLED;
- } else
+ /* At otg mode, the host does need to handle device interrupt */
+ if (hcd->self.is_b_host){
+ local_irq_restore(flags);
+ return IRQ_NONE;
+ }
+ else if (unlikely(hcd->state == HC_STATE_HALT ||
+ !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
rc = IRQ_NONE;
- } else if (unlikely(hcd->state == HC_STATE_HALT)) {
- rc = IRQ_NONE;
} else if (hcd->driver->irq(hcd) == IRQ_NONE) {
rc = IRQ_NONE;
} else {
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index d47201c75915..cc8f911afbc4 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1177,12 +1177,6 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
"Unsupported bus topology: hub nested too deep\n");
return -E2BIG;
}
-#ifdef CONFIG_PM
- /* Defaultly disable autosuspend for hub and reley on sys
- * to enable it.
- */
- hdev->autosuspend_disabled = 1;
-#endif
#ifdef CONFIG_USB_OTG_BLACKLIST_HUB
if (hdev->parent) {
@@ -2304,7 +2298,6 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev = hub->hdev;
unsigned port1;
-
/* fail if children aren't already suspended */
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
struct usb_device *udev;
@@ -2328,8 +2321,15 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
static int hub_resume(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata(intf);
+ struct usb_hcd *hcd = bus_to_hcd(hub->hdev->bus);
dev_dbg(&intf->dev, "%s\n", __func__);
+ /* At otg mode, if the hcd which the hub is attached to is not accessible,
+ * It should do nothing.
+ */
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
+ return 0;
+
hub_activate(hub, HUB_RESUME);
return 0;
}
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index ce44379bd172..c29ebda61b2f 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -466,7 +466,6 @@ config USB_GOKU
config USB_GADGET_ARC
boolean "Freescale USB Device Controller"
depends on ARCH_MXC || ARCH_STMP3XXX || ARCH_MXS
- depends on !USB_EHCI_ARC_OTG
select USB_GADGET_DUALSPEED
select USB_OTG_UTILS
select USB_GADGET_DUALSPEED if USB_GADGET_FSL_1504 || USB_GADGET_FSL_UTMI
@@ -792,6 +791,15 @@ config USB_G_PRINTER
For more information, see Documentation/usb/gadget_printer.txt
which includes sample code for accessing the device file.
+config USB_ANDROID
+ tristate "Android Gadget"
+ depends on SWITCH
+ help
+ The Android gadget provides mass storage and adb transport.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "g_android".
+
config USB_CDC_COMPOSITE
tristate "CDC Composite Device (Ethernet and ACM)"
depends on NET
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 477114e43372..545c0e256e28 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -41,6 +41,7 @@ gadgetfs-objs := inode.o
g_file_storage-objs := file_storage.o
g_printer-objs := printer.o
g_cdc-objs := cdc2.o
+g_android-objs := android.o f_adb.o f_mass_storage.o
obj-$(CONFIG_USB_ZERO) += g_zero.o
obj-$(CONFIG_USB_AUDIO) += g_audio.o
@@ -51,4 +52,5 @@ obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
obj-$(CONFIG_USB_G_PRINTER) += g_printer.o
obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
+obj-$(CONFIG_USB_ANDROID) += g_android.o
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c
index 1577c93c35bb..8e94549f891e 100644
--- a/drivers/usb/gadget/arcotg_udc.c
+++ b/drivers/usb/gadget/arcotg_udc.c
@@ -106,19 +106,6 @@ extern struct resource *otg_get_resources(void);
extern void fsl_platform_set_test_mode(struct fsl_usb2_platform_data *pdata, enum usb_test_mode mode);
-static inline void
-dr_wake_up_enable(struct fsl_udc *udc, bool enable)
-{
- struct fsl_usb2_platform_data *pdata;
- pdata = udc->pdata;
-
- if (enable && (!device_may_wakeup(udc_controller->gadget.dev.parent)))
- return;
-
- if (pdata->wake_up_enable)
- pdata->wake_up_enable(pdata, enable);
-}
-
#ifdef CONFIG_WORKAROUND_ARCUSB_REG_RW
static void safe_writel(u32 val32, void *addr)
{
@@ -177,6 +164,25 @@ static inline void dump_ep_queue(struct fsl_ep *ep)
}
#endif
+#if (defined CONFIG_ARCH_MX35 || defined CONFIG_ARCH_MX25)
+/*
+ * The Phy at MX35 and MX25 have bugs, it must disable, and re-eable phy
+ * if the phy clock is disabled before
+ */
+static void reset_phy(void)
+{
+ u32 phyctrl;
+ phyctrl = fsl_readl(&dr_regs->phyctrl1);
+ phyctrl &= ~PHY_CTRL0_USBEN;
+ fsl_writel(phyctrl, &dr_regs->phyctrl1);
+
+ phyctrl = fsl_readl(&dr_regs->phyctrl1);
+ phyctrl |= PHY_CTRL0_USBEN;
+ fsl_writel(phyctrl, &dr_regs->phyctrl1);
+}
+#else
+static void reset_phy(void){; }
+#endif
/*-----------------------------------------------------------------
* done() - retire a request; caller blocked irqs
* @status : request status to be set, only works when
@@ -264,9 +270,12 @@ static void done(struct fsl_ep *ep, struct fsl_req *req, int status)
static void nuke(struct fsl_ep *ep, int status)
{
ep->stopped = 1;
-
- /* Flush fifo */
- fsl_ep_fifo_flush(&ep->ep);
+ /*
+ * At udc stop mode, the clock is already off
+ * So flush fifo, should be done at clock on mode.
+ */
+ if (!ep->udc->stopped)
+ fsl_ep_fifo_flush(&ep->ep);
/* Whether this eq has request linked */
while (!list_empty(&ep->queue)) {
@@ -281,31 +290,85 @@ static void nuke(struct fsl_ep *ep, int status)
/*------------------------------------------------------------------
Internal Hardware related function
------------------------------------------------------------------*/
+static inline void
+dr_wake_up_enable(struct fsl_udc *udc, bool enable)
+{
+ struct fsl_usb2_platform_data *pdata;
+ pdata = udc->pdata;
-static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable)
+ if (pdata && pdata->wake_up_enable)
+ pdata->wake_up_enable(pdata, enable);
+}
+static bool clk_stoped = false;
+static inline void dr_clk_gate(bool on)
{
- u32 temp;
+ struct fsl_usb2_platform_data *pdata = udc_controller->pdata;
- if (!device_may_wakeup(udc_controller->gadget.dev.parent))
+ if (!pdata || !pdata->usb_clock_for_pm)
return;
+ if (on && clk_stoped) {
+ pdata->usb_clock_for_pm(true);
+ clk_stoped = false;
+ }
+ if (!on && !clk_stoped) {
+ pdata->usb_clock_for_pm(false);
+ clk_stoped = true;
+ }
+ if (on)
+ reset_phy();
+}
- if (enable) {
- temp = fsl_readl(&dr_regs->portsc1);
- temp |= PORTSCX_PHY_LOW_POWER_SPD;
- fsl_writel(temp, &dr_regs->portsc1);
+static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable)
+{
+ struct fsl_usb2_platform_data *pdata = udc->pdata;
+ u32 portsc;
- if (udc_controller->pdata->usb_clock_for_pm)
- udc_controller->pdata->usb_clock_for_pm(false);
+ if (pdata && pdata->phy_lowpower_suspend) {
+ pdata->phy_lowpower_suspend(enable);
} else {
- if (udc_controller->pdata->usb_clock_for_pm)
- udc_controller->pdata->usb_clock_for_pm(true);
-
- temp = fsl_readl(&dr_regs->portsc1);
- temp &= ~PORTSCX_PHY_LOW_POWER_SPD;
- fsl_writel(temp, &dr_regs->portsc1);
+ if (enable){
+ portsc = fsl_readl(&dr_regs->portsc1);
+ portsc |= PORTSCX_PHY_LOW_POWER_SPD;
+ fsl_writel(portsc, &dr_regs->portsc1);
+ } else {
+ portsc = fsl_readl(&dr_regs->portsc1);
+ portsc &= ~PORTSCX_PHY_LOW_POWER_SPD;
+ fsl_writel(portsc, &dr_regs->portsc1);
+ }
}
}
+
+/* workaroud for some boards, maybe there is a large capacitor between the ground and the Vbus
+ * that will cause the vbus dropping very slowly when device is detached,
+ * may cost 2-3 seconds to below 0.8V */
+static void udc_wait_b_session_low(void)
+{
+ u32 temp;
+ u32 wait = 5000; /* max wait time is 5000 ms */
+ /* if we are in host mode, don't need to care the B session */
+ if ((fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) == 0)
+ return;
+ /* if the udc is dettached , there will be a suspend irq */
+ if (udc_controller->usb_state != USB_STATE_SUSPENDED)
+ return;
+ temp = fsl_readl(&dr_regs->otgsc);
+ temp &= ~(OTGSC_B_SESSION_VALID_IRQ_EN );
+ fsl_writel(temp, &dr_regs->otgsc);
+
+ do {
+ if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_B_SESSION_VALID))
+ break;
+ mdelay(1);
+ wait -= 1;
+ } while(wait);
+ if (!wait)
+ printk("ERROR!!!!!: the vbus can not be lower then 0.8V for 5 seconds, Pls Check your HW design\n");
+ temp = fsl_readl(&dr_regs->otgsc);
+ temp |= (OTGSC_B_SESSION_VALID_IRQ_EN );
+ fsl_writel(temp, &dr_regs->otgsc);
+}
+
static int dr_controller_setup(struct fsl_udc *udc)
{
unsigned int tmp = 0, portctrl = 0;
@@ -427,37 +490,36 @@ static void dr_controller_run(struct fsl_udc *udc)
fsl_writel(temp, &dr_regs->usbintr);
- if (device_may_wakeup(udc_controller->gadget.dev.parent)) {
- /* enable BSV irq */
- temp = fsl_readl(&dr_regs->otgsc);
- temp |= OTGSC_B_SESSION_VALID_IRQ_EN;
- fsl_writel(temp, &dr_regs->otgsc);
- }
+ /* enable BSV irq */
+ temp = fsl_readl(&dr_regs->otgsc);
+ temp |= OTGSC_B_SESSION_VALID_IRQ_EN;
+ fsl_writel(temp, &dr_regs->otgsc);
/* If vbus not on and used low power mode */
- if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_B_SESSION_VALID)
- && device_may_wakeup(udc_controller->gadget.dev.parent)) {
- /* enable wake up */
- dr_wake_up_enable(udc, true);
+ if (!(temp & OTGSC_B_SESSION_VALID)) {
/* Set stopped before low power mode */
udc->stopped = 1;
- /* close PHY clock */
+ /* enable wake up */
+ dr_wake_up_enable(udc, true);
+ /* enter lower power mode */
dr_phy_low_power_mode(udc, true);
- printk(KERN_INFO "udc enter low power mode \n");
+ printk(KERN_INFO "%s: udc enter low power mode \n", __func__);
} else {
+#ifdef CONFIG_ARCH_MX37
/*
add some delay for USB timing issue. USB may be
recognize as FS device
during USB gadget remote wake up function
*/
mdelay(100);
+#endif
/* Clear stopped bit */
udc->stopped = 0;
- /* Set controller to Run */
+
+ /* The usb line has already been connected to pc */
temp = fsl_readl(&dr_regs->usbcmd);
temp |= USB_CMD_RUN_STOP;
fsl_writel(temp, &dr_regs->usbcmd);
- printk(KERN_INFO "udc run \n");
}
return;
@@ -680,7 +742,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
case USB_ENDPOINT_XFER_ISOC:
/* Calculate transactions needed for high bandwidth iso */
mult = (unsigned char)(1 + ((max >> 11) & 0x03));
- max = max & 0x8ff; /* bit 0~10 */
+ max = max & 0x7ff; /* bit 0~10 */
/* 3 transactions at most */
if (mult > 3)
goto en_done;
@@ -1953,15 +2015,36 @@ static void suspend_irq(struct fsl_udc *udc)
udc->driver->suspend(&udc->gadget);
}
-/* Process Wake up interrupt */
-static void wake_up_irq(struct fsl_udc *udc)
-{
- pr_debug("%s\n", __func__);
-
- /* disable wake up irq */
- dr_wake_up_enable(udc_controller, false);
-
- udc->stopped = 0;
+/* Process Wake up interrupt
+ * Be careful that some boards will use ID pin to control the VBUS on/off
+ * in these case, after the device enter the lowpower mode(clk off,
+ * phy lowpower mode, wakeup enable), then an udisk is attaced to the otg port,
+ * there will be an Vbus wakeup event and then an ID change wakeup, But the Vbus
+ * event is not expected, so there is an workaround that will detect the ID, if ID=0
+ * we just need the ID event so we can not disable the wakeup
+ *
+ * false: host wakeup event
+ * true: device wakeup event
+*/
+static bool wake_up_irq(struct fsl_udc *udc)
+{
+ /* Because the IC design needs to remove the glitch on ID so the otgsc bit 8 will
+ * be delayed max 2 ms to show the real ID pin value
+ */
+ mdelay(3);
+
+ /* if the ID=0, let arc host process the wakeup */
+ if (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) {
+ dr_wake_up_enable(udc_controller, false);
+ dr_phy_low_power_mode(udc, false);
+ printk("device wake up event\n");
+ return true;
+ }else {/* wakeup is vbus wake event, but not for device so we need to clear b session */
+ int irq_src = fsl_readl(&dr_regs->otgsc) & (~OTGSC_ID_CHANGE_IRQ_STS);
+ fsl_writel(irq_src, &dr_regs->otgsc);
+ printk("The host wakeup event, should be handled by host\n");
+ return false;
+ }
}
static void bus_resume(struct fsl_udc *udc)
@@ -2018,72 +2101,60 @@ static void reset_irq(struct fsl_udc *udc)
/* Write 1s to the flush register */
fsl_writel(0xffffffff, &dr_regs->endptflush);
- if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) {
- VDBG("Bus reset");
- /* Bus is reseting */
- udc->bus_reset = 1;
- /* Reset all the queues, include XD, dTD, EP queue
- * head and TR Queue */
- reset_queues(udc);
- udc->usb_state = USB_STATE_DEFAULT;
- } else {
- VDBG("Controller reset");
- /* initialize usb hw reg except for regs for EP, not
- * touch usbintr reg */
- dr_controller_setup(udc);
-
- /* Reset all internal used Queues */
- reset_queues(udc);
-
- ep0_setup(udc);
-
- /* Enable DR IRQ reg, Set Run bit, change udc state */
- dr_controller_run(udc);
- udc->usb_state = USB_STATE_ATTACHED;
- }
+ /* Bus is reseting */
+ udc->bus_reset = 1;
+ /* Reset all the queues, include XD, dTD, EP queue
+ * head and TR Queue */
+ reset_queues(udc);
+ udc->usb_state = USB_STATE_DEFAULT;
}
/* if wakup udc, return true; else return false*/
bool try_wake_up_udc(struct fsl_udc *udc)
{
u32 irq_src;
+ bool b_device;
/* when udc is stopped, only handle wake up irq */
if (udc->stopped) {
- if (!device_may_wakeup(&(udc->pdata->pdev->dev)))
- return false;
-
- dr_phy_low_power_mode(udc_controller, false);
-
/* check to see if wake up irq */
irq_src = fsl_readl(&dr_regs->usbctrl);
if (irq_src & USB_CTRL_OTG_WUIR) {
- wake_up_irq(udc);
- } else {
- dr_phy_low_power_mode(udc_controller, true);
+ if (wake_up_irq(udc) == false){
+ return false; /* host wakeup event */
+ }
}
}
- if (!device_may_wakeup(udc_controller->gadget.dev.parent))
- return true;
-
/* check if Vbus change irq */
irq_src = fsl_readl(&dr_regs->otgsc);
if (irq_src & OTGSC_B_SESSION_VALID_IRQ_STS) {
u32 tmp;
+ /* Because the IC design needs to remove the glitch on ID so the otgsc bit 8 will
+ * be delayed max 2 ms to show the real ID pin value, as it needs to use ID to judge
+ * host or device
+ */
+ mdelay(3);
+ b_device = (irq_src & OTGSC_STS_USB_ID)? true:false;
fsl_writel(irq_src, &dr_regs->otgsc);
+ if (!b_device)
+ return false;
tmp = fsl_readl(&dr_regs->usbcmd);
/* check BSV bit to see if fall or rise */
if (irq_src & OTGSC_B_SESSION_VALID) {
+ if (udc->suspended) /*let the system pm resume the udc */
+ return true;
udc->stopped = 0;
fsl_writel(tmp | USB_CMD_RUN_STOP, &dr_regs->usbcmd);
- printk(KERN_INFO "udc out low power mode\n");
+ printk(KERN_INFO "%s: udc out low power mode\n", __func__);
} else {
- printk(KERN_INFO "udc enter low power mode \n");
+ printk(KERN_INFO "%s: udc enter low power mode \n", __func__);
+ if (udc->driver)
+ udc->driver->disconnect(&udc->gadget);
fsl_writel(tmp & ~USB_CMD_RUN_STOP, &dr_regs->usbcmd);
+ udc->stopped = 1;
/* enable wake up */
dr_wake_up_enable(udc, true);
- udc->stopped = 1;
/* close USB PHY clock */
dr_phy_low_power_mode(udc, true);
return false;
@@ -2092,7 +2163,6 @@ bool try_wake_up_udc(struct fsl_udc *udc)
return true;
}
-
/*
* USB device controller interrupt handler
*/
@@ -2103,15 +2173,29 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
irqreturn_t status = IRQ_NONE;
unsigned long flags;
- if (try_wake_up_udc(udc) == false)
- return IRQ_NONE;
-
spin_lock_irqsave(&udc->lock, flags);
+ if (udc->stopped)
+ dr_clk_gate(true);
+
+ if (try_wake_up_udc(udc) == false) {
+ goto irq_end;
+ }
+#ifdef CONFIG_USB_OTG
+ /* if no gadget register in this driver, we need do noting */
+ if (udc->transceiver->gadget == NULL)
+ goto irq_end;
+
+ /* only handle device interrupt event */
+ if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) {
+ goto irq_end;
+ }
+#endif
+
irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr);
/* Clear notification bits */
fsl_writel(irq_src, &dr_regs->usbsts);
- /* VDBG("irq_src [0x%8x]", irq_src); */
+ VDBG("0x%x\n", irq_src);
/* Need to resume? */
if (udc->usb_state == USB_STATE_SUSPENDED)
@@ -2156,12 +2240,24 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
/* Sleep Enable (Suspend) */
if (irq_src & USB_STS_SUSPEND) {
+ VDBG("suspend int");
suspend_irq(udc);
status = IRQ_HANDLED;
}
if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) {
- VDBG("Error IRQ %x ", irq_src);
+ printk(KERN_ERR "Error IRQ %x ", irq_src);
+ if (irq_src & USB_STS_SYS_ERR) {
+ printk(KERN_ERR "This error can't be recoveried, \
+ please reboot your board\n");
+ printk(KERN_ERR "If this error happens frequently, \
+ please check your dma buffer\n");
+ }
+ }
+
+irq_end:
+ if (udc->stopped){
+ dr_clk_gate(false);
}
spin_unlock_irqrestore(&udc->lock, flags);
@@ -2176,9 +2272,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
{
int retval = -ENODEV;
unsigned long flags = 0;
-#ifndef CONFIG_USB_OTG
- u32 portsc;
-#endif
if (!udc_controller)
return -ENODEV;
@@ -2196,18 +2289,19 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
spin_lock_irqsave(&udc_controller->lock, flags);
driver->driver.bus = 0;
+ udc_controller->pdata->port_enables = 1;
/* hook up the driver */
udc_controller->driver = driver;
udc_controller->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc_controller->lock, flags);
-#ifndef CONFIG_USB_OTG
- if (udc_controller->pdata->usb_clock_for_pm)
- udc_controller->pdata->usb_clock_for_pm(true);
+ dr_clk_gate(true);
+ /* It doesn't need to switch usb from low power mode to normal mode
+ * at otg mode
+ */
+ if (!udc_controller->transceiver){
+ dr_phy_low_power_mode(udc_controller, false);
+ }
- portsc = fsl_readl(&dr_regs->portsc1);
- portsc &= ~PORTSCX_PHY_LOW_POWER_SPD;
- fsl_writel(portsc, &dr_regs->portsc1);
-#endif
/* bind udc driver to gadget driver */
retval = driver->bind(&udc_controller->gadget);
if (retval) {
@@ -2219,30 +2313,30 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
if (udc_controller->transceiver) {
/* Suspend the controller until OTG enable it */
- udc_controller->stopped = 1;
+ udc_controller->suspended = 1;/* let the otg resume it */
printk(KERN_INFO "Suspend udc for OTG auto detect\n");
dr_wake_up_enable(udc_controller, true);
- dr_phy_low_power_mode(udc_controller, true);
/* export udc suspend/resume call to OTG */
udc_controller->gadget.dev.driver->suspend = (dev_sus)fsl_udc_suspend;
udc_controller->gadget.dev.driver->resume = (dev_res)fsl_udc_resume;
/* connect to bus through transceiver */
- if (udc_controller->transceiver) {
- retval = otg_set_peripheral(udc_controller->transceiver,
- &udc_controller->gadget);
- if (retval < 0) {
- ERR("can't bind to transceiver\n");
- driver->unbind(&udc_controller->gadget);
- udc_controller->gadget.dev.driver = 0;
- udc_controller->driver = 0;
- return retval;
- }
+ retval = otg_set_peripheral(udc_controller->transceiver,
+ &udc_controller->gadget);
+ if (retval < 0) {
+ ERR("can't bind to transceiver\n");
+ driver->unbind(&udc_controller->gadget);
+ udc_controller->gadget.dev.driver = 0;
+ udc_controller->driver = 0;
+ return retval;
}
+ //dr_clk_gate(false);
} else {
/* Enable DR IRQ reg and Set usbcmd reg Run bit */
dr_controller_run(udc_controller);
+ if (udc_controller->stopped)
+ dr_clk_gate(false);
udc_controller->usb_state = USB_STATE_ATTACHED;
udc_controller->ep0_dir = 0;
}
@@ -2250,8 +2344,10 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
udc_controller->gadget.name, driver->driver.name);
out:
- if (retval)
+ if (retval){
printk(KERN_DEBUG "retval %d \n", retval);
+ udc_controller->pdata->port_enables = 0;
+ }
return retval;
}
EXPORT_SYMBOL(usb_gadget_register_driver);
@@ -2261,7 +2357,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
{
struct fsl_ep *loop_ep;
unsigned long flags;
- u32 portsc;
if (!udc_controller)
return -ENODEV;
@@ -2269,15 +2364,16 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
if (!driver || driver != udc_controller->driver || !driver->unbind)
return -EINVAL;
+ if(udc_controller->stopped)
+ dr_clk_gate(true);
+
if (udc_controller->transceiver)
(void)otg_set_peripheral(udc_controller->transceiver, 0);
- /* open phy clock for following operation */
- dr_phy_low_power_mode(udc_controller, false);
-
/* stop DR, disable intr */
dr_controller_stop(udc_controller);
+ udc_controller->pdata->port_enables = 0;
/* in fact, no needed */
udc_controller->usb_state = USB_STATE_ATTACHED;
udc_controller->ep0_dir = 0;
@@ -2299,14 +2395,11 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
udc_controller->gadget.dev.driver = 0;
udc_controller->driver = 0;
- dr_wake_up_enable(udc_controller, false);
-
- portsc = fsl_readl(&dr_regs->portsc1);
- portsc |= PORTSCX_PHY_LOW_POWER_SPD;
- fsl_writel(portsc, &dr_regs->portsc1);
+ if (udc_controller->gadget.is_otg) {
+ dr_wake_up_enable(udc_controller, true);
+ }
- if (udc_controller->pdata->usb_clock_for_pm)
- udc_controller->pdata->usb_clock_for_pm(false);
+ dr_phy_low_power_mode(udc_controller, true);
printk(KERN_INFO "unregistered gadget driver '%s'\r\n",
driver->driver.name);
@@ -2705,14 +2798,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
int ret = -ENODEV;
unsigned int i;
u32 dccparams;
-#ifndef CONFIG_USB_OTG
- u32 portsc;
-#endif
-
- if (strcmp(pdev->name, driver_name)) {
- VDBG("Wrong device\n");
- return -ENODEV;
- }
udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL);
if (udc_controller == NULL) {
@@ -2729,6 +2814,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
ret = -ENODEV;
goto err1a;
}
+ udc_controller->gadget.is_otg = 1;
#endif
if ((pdev->dev.parent) &&
@@ -2768,6 +2854,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
goto err2a;
}
+ /* Due to mx35/mx25's phy's bug */
+ reset_phy();
+
if (pdata->have_sysif_regs)
usb_sys_regs = (struct usb_sys_interface *)
((u32)dr_regs + USB_DR_SYS_OFFSET);
@@ -2826,12 +2915,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
if (ret < 0)
goto err3;
- if (udc_controller->transceiver) {
- udc_controller->gadget.is_otg = 1;
- /* now didn't support lpm in OTG mode*/
- device_set_wakeup_capable(&pdev->dev, 0);
- }
-
/* setup QH and epctrl for ep0 */
ep0_setup(udc_controller);
@@ -2874,20 +2957,29 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
#ifdef POSTPONE_FREE_LAST_DTD
last_free_td = NULL;
#endif
+
#ifndef CONFIG_USB_OTG
/* disable all INTR */
fsl_writel(0, &dr_regs->usbintr);
-
dr_wake_up_enable(udc_controller, false);
+#else
+ dr_wake_up_enable(udc_controller, true);
+#endif
+
+/*
+ * As mx25/mx35 does not implement clk_gate, should not let phy to low
+ * power mode due to IC bug
+ */
+#if !(defined CONFIG_ARCH_MX35 || defined CONFIG_ARCH_MX25)
+{
+ dr_phy_low_power_mode(udc_controller, true);
+}
+#endif
udc_controller->stopped = 1;
- portsc = fsl_readl(&dr_regs->portsc1);
- portsc |= PORTSCX_PHY_LOW_POWER_SPD;
- fsl_writel(portsc, &dr_regs->portsc1);
+ /* let the gadget register function open the clk */
+ dr_clk_gate(false);
- if (udc_controller->pdata->usb_clock_for_pm)
- udc_controller->pdata->usb_clock_for_pm(false);
-#endif
create_proc_file();
return 0;
@@ -2914,9 +3006,6 @@ err1a:
*/
static int __exit fsl_udc_remove(struct platform_device *pdev)
{
-#ifndef CONFIG_USB_OTG
- struct resource *res;
-#endif
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
DECLARE_COMPLETION(done);
@@ -2925,7 +3014,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
return -ENODEV;
udc_controller->done = &done;
/* open USB PHY clock */
- dr_phy_low_power_mode(udc_controller, false);
+ if (udc_controller->stopped)
+ dr_clk_gate(true);
/* DR has been stopped in usb_gadget_unregister_driver() */
remove_proc_file();
@@ -2948,8 +3038,11 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
iounmap((u8 __iomem *)dr_regs);
#ifndef CONFIG_USB_OTG
+{
+ struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
+}
#endif
device_unregister(&udc_controller->gadget.dev);
@@ -2963,6 +3056,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
if (pdata->platform_uninit)
pdata->platform_uninit(pdata);
+ if (udc_controller->stopped)
+ dr_clk_gate(false);
return 0;
}
@@ -2970,10 +3065,19 @@ static int udc_suspend(struct fsl_udc *udc)
{
u32 mode, usbcmd;
- /* open clock for register access */
- if (udc_controller->pdata->usb_clock_for_pm)
- udc_controller->pdata->usb_clock_for_pm(true);
-
+ /*
+ * When it is the PM suspend routine and the device has no
+ * abilities to wakeup system, it should not set wakeup enable.
+ * Otherwise, the system will wakeup even the user only wants to
+ * charge using usb
+ */
+ if (udc_controller->gadget.dev.parent->power.status
+ == DPM_SUSPENDING) {
+ if (!device_may_wakeup(udc_controller->gadget.dev.parent))
+ dr_wake_up_enable(udc, false);
+ else
+ dr_wake_up_enable(udc, true);
+ }
mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK;
usbcmd = fsl_readl(&dr_regs->usbcmd);
@@ -2984,9 +3088,8 @@ static int udc_suspend(struct fsl_udc *udc)
* PM suspend. Remember this fact, so that we will leave the
* controller stopped at PM resume time.
*/
- if (udc->stopped) {
+ if (udc->suspended) {
pr_debug("gadget already stopped, leaving early\n");
- udc->already_stopped = 1;
goto out;
}
@@ -2995,22 +3098,30 @@ static int udc_suspend(struct fsl_udc *udc)
goto out;
}
+ /* For some buggy hardware designs, see comment of this function for detail */
+ udc_wait_b_session_low();
+
udc->stopped = 1;
- /* if the suspend is not for switch to host in otg mode */
- if ((!(udc->gadget.is_otg)) ||
- (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) {
- dr_wake_up_enable(udc, true);
- dr_phy_low_power_mode(udc, true);
- }
/* stop the controller */
usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP;
fsl_writel(usbcmd, &dr_regs->usbcmd);
+ /* if the suspend is not for switch to host in otg mode */
+ if ((!(udc->gadget.is_otg)) ||
+ (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) {
+ if (device_may_wakeup(udc_controller->gadget.dev.parent)) {
+ dr_wake_up_enable(udc, true);
+ }
+ }
+
+ dr_phy_low_power_mode(udc, true);
printk(KERN_INFO "USB Gadget suspended\n");
out:
- if (udc_controller->pdata->usb_clock_for_pm)
- udc_controller->pdata->usb_clock_for_pm(false);
+ udc->suspended++;
+ if (udc->suspended > 2)
+ printk("ERROR: suspended times > 2\n");
+
return 0;
}
@@ -3020,13 +3131,24 @@ out:
-----------------------------------------------------------------*/
static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state)
{
+ int ret;
+#ifdef CONFIG_USB_OTG
+ if (udc_controller->transceiver->gadget == NULL)
+ return 0;
+#endif
+ if (udc_controller->stopped)
+ dr_clk_gate(true);
if (((!(udc_controller->gadget.is_otg)) ||
(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) &&
(udc_controller->usb_state > USB_STATE_POWERED) &&
- (udc_controller->usb_state < USB_STATE_SUSPENDED))
- return -EBUSY;
+ (udc_controller->usb_state < USB_STATE_SUSPENDED)) {
+ return -EBUSY;/* keep the clk on */
+ }
+ else
+ ret = udc_suspend(udc_controller);
+ dr_clk_gate(false);
- return udc_suspend(udc_controller);
+ return ret;
}
/*-----------------------------------------------------------------
@@ -3035,30 +3157,54 @@ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state)
*-----------------------------------------------------------------*/
static int fsl_udc_resume(struct platform_device *pdev)
{
- pr_debug("%s(): stopped %d already_stopped %d\n", __func__,
- udc_controller->stopped, udc_controller->already_stopped);
-
+ pr_debug("%s(): stopped %d suspended %d\n", __func__,
+ udc_controller->stopped, udc_controller->suspended);
+ printk("udc resume\n");
+#ifdef CONFIG_USB_OTG
+ if (udc_controller->transceiver->gadget == NULL)
+ return 0;
+#endif
+ if (udc_controller->stopped)
+ dr_clk_gate(true);
/*
* If the controller was stopped at suspend time, then
* don't resume it now.
*/
- if (udc_controller->already_stopped) {
- udc_controller->already_stopped = 0;
- pr_debug("gadget was already stopped, leaving early\n");
- return 0;
- }
+ /*
+ * If it is PM resume routine, the udc is at low power mode,
+ * and the udc has no abilities to wakeup system, it should
+ * set the abilities to wakeup itself. Otherwise, the usb
+ * subsystem will not leave from low power mode.
+ */
+ if (!device_may_wakeup(udc_controller->gadget.dev.parent) &&
+ udc_controller->gadget.dev.parent->power.status
+ == DPM_RESUMING){
+ dr_wake_up_enable(udc_controller, true);
+ }
+ if (--udc_controller->suspended) {
+ printk("gadget was already stopped, leaving early\n");
+ goto out;
+ }
/* Enable DR irq reg and set controller Run */
if (udc_controller->stopped) {
+ /* if in host mode, we need to do nothing */
+ if ((fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) == 0) {
+ goto out;
+ }
dr_wake_up_enable(udc_controller, false);
dr_phy_low_power_mode(udc_controller, false);
- mdelay(1);
-
+ mdelay(10);
dr_controller_setup(udc_controller);
dr_controller_run(udc_controller);
}
udc_controller->usb_state = USB_STATE_ATTACHED;
udc_controller->ep0_dir = 0;
+out:
+ /* if udc is resume by otg id change and no device
+ * connecting to the otg, otg will enter low power mode*/
+ if (udc_controller->stopped)
+ dr_clk_gate(false);
printk(KERN_INFO "USB Gadget resumed\n");
return 0;
diff --git a/drivers/usb/gadget/arcotg_udc.h b/drivers/usb/gadget/arcotg_udc.h
index 480d953dcf58..8d344acb8fef 100644
--- a/drivers/usb/gadget/arcotg_udc.h
+++ b/drivers/usb/gadget/arcotg_udc.h
@@ -266,6 +266,7 @@ struct usb_sys_interface {
#define PORTSCX_SPEED_BIT_POS (26)
/* OTGSC Register Bit Masks */
+#define OTGSC_ID_CHANGE_IRQ_STS (1 << 16)
#define OTGSC_B_SESSION_VALID_IRQ_EN (1 << 27)
#define OTGSC_B_SESSION_VALID_IRQ_STS (1 << 19)
#define OTGSC_B_SESSION_VALID (1 << 11)
@@ -365,6 +366,7 @@ struct usb_sys_interface {
/* PHY control0 Register Bit Masks */
#define PHY_CTRL0_CONF2 (1 << 26)
+#define PHY_CTRL0_USBEN (1 << 24) /* USB UTMI PHY Enable */
/* USB UH2 CTRL Register Bits */
#define USB_UH2_OVBWK_EN (1 << 6) /* OTG VBUS Wakeup Enable */
@@ -592,9 +594,15 @@ struct fsl_udc {
struct otg_transceiver *transceiver;
unsigned softconnect:1;
unsigned vbus_active:1;
- unsigned stopped:1;
unsigned remote_wakeup:1;
- unsigned already_stopped:1;
+ /* we must distinguish the stopped and suspended state,
+ * stopped means the udc enter lowpower mode, suspended
+ * means the udc is suspended by system pm or by otg
+ * switching to host mode.if the udc in suspended state
+ * it also in the stopped state, while if the udc in
+ * stopped state,it may not be in the suspended state*/
+ unsigned stopped:1;
+ int suspended;
struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */
struct fsl_req *status_req; /* ep0 status request */
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 59e85234fa0a..2e79b8c389a4 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -236,6 +236,7 @@ static int config_buf(struct usb_configuration *config,
int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE;
struct usb_function *f;
int status;
+ int interfaceCount = 0;
/* write the config descriptor */
c = buf;
@@ -266,8 +267,16 @@ static int config_buf(struct usb_configuration *config,
descriptors = f->hs_descriptors;
else
descriptors = f->descriptors;
- if (!descriptors)
+ if (f->hidden || !descriptors || descriptors[0] == NULL) {
+ for (; f != config->interface[interfaceCount];) {
+ interfaceCount++;
+ c->bNumInterfaces--;
+ }
continue;
+ }
+ for (; f != config->interface[interfaceCount];)
+ interfaceCount++;
+
status = usb_descriptor_fillbuf(next, len,
(const struct usb_descriptor_header **) descriptors);
if (status < 0)
@@ -756,11 +765,11 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
case USB_REQ_GET_CONFIGURATION:
if (ctrl->bRequestType != USB_DIR_IN)
goto unknown;
- if (cdev->config)
+ if (cdev->config) {
*(u8 *)req->buf = cdev->config->bConfigurationValue;
- else
+ value = min(w_length, (u16) 1);
+ } else
*(u8 *)req->buf = 0;
- value = min(w_length, (u16) 1);
break;
/* function drivers must handle get/set altsetting; if there's
@@ -810,6 +819,9 @@ unknown:
*/
if ((ctrl->bRequestType & USB_RECIP_MASK)
== USB_RECIP_INTERFACE) {
+ if (cdev->config == NULL)
+ return value;
+
f = cdev->config->interface[intf];
if (f && f->setup)
value = f->setup(f, ctrl);
@@ -824,6 +836,25 @@ unknown:
value = c->setup(c, ctrl);
}
+ /* If the vendor request is not processed (value < 0),
+ * call all device registered configure setup callbacks
+ * to process it.
+ * This is used to handle the following cases:
+ * - vendor request is for the device and arrives before
+ * setconfiguration.
+ * - Some devices are required to handle vendor request before
+ * setconfiguration such as MTP, USBNET.
+ */
+
+ if (value < 0) {
+ struct usb_configuration *cfg;
+
+ list_for_each_entry(cfg, &cdev->configs, list) {
+ if (cfg && cfg->setup)
+ value = cfg->setup(cfg, ctrl);
+ }
+ }
+
goto done;
}
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 7953948bfe4a..7dd1a8bbe382 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -761,3 +761,12 @@ int __init acm_bind_config(struct usb_configuration *c, u8 port_num)
kfree(acm);
return status;
}
+
+int __init acm_function_add(struct usb_composite_dev *cdev,
+ struct usb_configuration *c)
+{
+ int ret = acm_bind_config(c, 0);
+ if (ret == 0)
+ gserial_setup(c->cdev->gadget, 1);
+ return ret;
+}
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 66105ce49672..8b0a13202573 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -728,6 +728,7 @@ struct fsg_dev {
#include "fsl_updater.h"
#endif
+static int do_set_interface(struct fsg_dev *fsg, int altsetting);
typedef void (*fsg_routine_t)(struct fsg_dev *);
static int exception_in_progress(struct fsg_dev *fsg)
@@ -1108,6 +1109,14 @@ static void fsg_disconnect(struct usb_gadget *gadget)
struct fsg_dev *fsg = get_gadget_data(gadget);
DBG(fsg, "disconnect or port reset\n");
+ /*
+ * The disconnect exception will call do_set_config, and therefore will
+ * visit controller registers. However it is a delayed event, and will be
+ * handled at another process, so the controller maybe have already close the
+ * usb clock.*/
+ if (fsg->new_config)
+ do_set_interface(fsg, -1);/* disable the interface */
+
raise_exception(fsg, FSG_STATE_DISCONNECT);
}
diff --git a/drivers/usb/gadget/fsl_updater.c b/drivers/usb/gadget/fsl_updater.c
index 8b4b54f8cca7..50acce441a90 100644
--- a/drivers/usb/gadget/fsl_updater.c
+++ b/drivers/usb/gadget/fsl_updater.c
@@ -29,6 +29,7 @@ static int utp_init(struct fsg_dev *fsg)
INIT_LIST_HEAD(&utp_context.write);
mutex_init(&utp_context.lock);
+ /* the max message is 64KB */
utp_context.buffer = vmalloc(0x10000);
if (!utp_context.buffer)
return -EIO;
@@ -63,6 +64,7 @@ static void utp_user_data_free(struct utp_user_data *uud)
kfree(uud);
}
+/* Get the number of element for list */
static u32 count_list(struct list_head *l)
{
u32 count = 0;
@@ -74,10 +76,11 @@ static u32 count_list(struct list_head *l)
return count;
}
-
+/* The routine will not go on if utp_context.queue is empty */
#define WAIT_ACTIVITY(queue) \
wait_event_interruptible(utp_context.wq, !list_empty(&utp_context.queue))
+/* Called by userspace program (uuc) */
static ssize_t utp_file_read(struct file *file,
char __user *buf,
size_t size,
@@ -109,12 +112,15 @@ static ssize_t utp_file_read(struct file *file,
"need to put %d\n", size, size_to_put);
}
+ /*
+ * The user program has already finished data process,
+ * go on getting data from the host
+ */
wake_up(&utp_context.list_full_wq);
return size_to_put;
}
-
static ssize_t utp_file_write(struct file *file, const char __user *buf,
size_t size, loff_t *off)
{
@@ -127,11 +133,13 @@ static ssize_t utp_file_write(struct file *file, const char __user *buf,
return -EACCES;
mutex_lock(&utp_context.lock);
list_add_tail(&uud->link, &utp_context.write);
+ /* Go on EXEC routine process */
wake_up(&utp_context.wq);
mutex_unlock(&utp_context.lock);
return size;
}
+/* Will be called when the host wants to get the sense data */
static int utp_get_sense(struct fsg_dev *fsg)
{
if (UTP_CTX(fsg)->processed == 0)
@@ -186,6 +194,7 @@ static int utp_do_read(struct fsg_dev *fsg, void *data, size_t size)
/* Perform the read */
pr_info("Copied to %p, %d bytes started from %d\n",
bh->buf, amount, size - amount_left);
+ /* from upt buffer to file_storeage buffer */
memcpy(bh->buf, data + size - amount_left, amount);
amount_left -= amount;
fsg->residue -= amount;
@@ -196,6 +205,7 @@ static int utp_do_read(struct fsg_dev *fsg, void *data, size_t size)
/* Send this buffer and go read some more */
bh->inreq->zero = 0;
+ /* USB Physical transfer: Data from device to host */
start_transfer(fsg, fsg->bulk_in, bh->inreq,
&bh->inreq_busy, &bh->state);
@@ -326,8 +336,8 @@ static void utp_poll(struct fsg_dev *fsg)
if (uud) {
if (uud->data.flags & UTP_FLAG_STATUS) {
- pr_debug("%s: exit with status %d\n", __func__,
- uud->data.status);
+ printk(KERN_WARNING "%s: exit with status %d\n",
+ __func__, uud->data.status);
UTP_SS_EXIT(fsg, uud->data.status);
} else {
pr_debug("%s: pass\n", __func__);
@@ -356,11 +366,16 @@ static int utp_exec(struct fsg_dev *fsg,
mutex_lock(&ctx->lock);
list_add_tail(&uud2r->link, &ctx->read);
mutex_unlock(&ctx->lock);
+ /* wake up the read routine */
wake_up(&ctx->wq);
if (command[0] == '!') /* there will be no response */
return 0;
+ /*
+ * the user program (uuc) will return utp_message
+ * and add list to write list
+ */
WAIT_ACTIVITY(write);
mutex_lock(&ctx->lock);
@@ -382,21 +397,19 @@ static int utp_exec(struct fsg_dev *fsg,
if (uud->data.flags & UTP_FLAG_DATA) {
memcpy(ctx->buffer, uud->data.data, uud->data.bufsize);
UTP_SS_SIZE(fsg, uud->data.bufsize);
- utp_user_data_free(uud);
- return 0;
- }
-
- if (uud->data.flags & UTP_FLAG_REPORT_BUSY) {
- utp_user_data_free(uud);
+ } else if (uud->data.flags & UTP_FLAG_REPORT_BUSY) {
ctx->counter = 0xFFFF;
UTP_SS_BUSY(fsg, ctx->counter);
- return 0;
+ } else if (uud->data.flags & UTP_FLAG_STATUS) {
+ printk(KERN_WARNING "%s: exit with status %d\n", __func__,
+ uud->data.status);
+ UTP_SS_EXIT(fsg, uud->data.status);
+ } else {
+ pr_debug("%s: pass\n", __func__);
+ UTP_SS_PASS(fsg);
}
-
utp_user_data_free(uud);
- UTP_SS_PASS(fsg);
-
- return -1;
+ return 0;
}
static int utp_send_status(struct fsg_dev *fsg)
@@ -470,16 +483,17 @@ static int utp_handle_message(struct fsg_dev *fsg,
case UTP_EXEC:
pr_debug("%s: EXEC\n", __func__);
data = kzalloc(fsg->data_size, GFP_KERNEL);
+ /* copy data from usb buffer to utp buffer */
utp_do_write(fsg, data, fsg->data_size);
utp_exec(fsg, data, fsg->data_size, param);
kfree(data);
break;
- case UTP_GET:
+ case UTP_GET: /* data from device to host */
pr_debug("%s: GET, %d bytes\n", __func__, fsg->data_size);
r = utp_do_read(fsg, UTP_CTX(fsg)->buffer, fsg->data_size);
UTP_SS_PASS(fsg);
break;
- case UTP_PUT:
+ case UTP_PUT: /* data from host to device */
pr_debug("%s: PUT, %d bytes\n", __func__, fsg->data_size);
uud2r = utp_user_data_alloc(fsg->data_size);
uud2r->data.bufsize = fsg->data_size;
@@ -490,6 +504,37 @@ static int utp_handle_message(struct fsg_dev *fsg,
list_add_tail(&uud2r->link, &UTP_CTX(fsg)->read);
mutex_unlock(&UTP_CTX(fsg)->lock);
wake_up(&UTP_CTX(fsg)->wq);
+ /*
+ * Return PASS or FAIL according to uuc's status
+ * Please open it if need to check uuc's status
+ * and use another version uuc
+ */
+#if 0
+ struct utp_user_data *uud = NULL;
+ struct utp_context *ctx;
+ WAIT_ACTIVITY(write);
+ ctx = UTP_CTX(fsg);
+ mutex_lock(&ctx->lock);
+
+ if (!list_empty(&ctx->write))
+ uud = list_first_entry(&ctx->write,
+ struct utp_user_data, link);
+
+ mutex_unlock(&ctx->lock);
+ if (uud) {
+ if (uud->data.flags & UTP_FLAG_STATUS) {
+ printk(KERN_WARNING "%s: exit with status %d\n",
+ __func__, uud->data.status);
+ UTP_SS_EXIT(fsg, uud->data.status);
+ } else {
+ pr_debug("%s: pass\n", __func__);
+ UTP_SS_PASS(fsg);
+ }
+ utp_user_data_free(uud);
+ } else{
+ UTP_SS_PASS(fsg);
+ }
+#endif
UTP_SS_PASS(fsg);
wait_event_interruptible(UTP_CTX(fsg)->list_full_wq,
diff --git a/drivers/usb/gadget/fsl_updater.h b/drivers/usb/gadget/fsl_updater.h
index 44329a9af58a..70e4defa1a9c 100644
--- a/drivers/usb/gadget/fsl_updater.h
+++ b/drivers/usb/gadget/fsl_updater.h
@@ -59,6 +59,7 @@ static int utp_handle_message(struct fsg_dev *fsg,
#define UTP_SS_BUSY(fsg, r) utp_set_sense(fsg, UTP_REPLY_BUSY, (u64)r)
#define UTP_SS_SIZE(fsg, r) utp_set_sense(fsg, UTP_REPLY_SIZE, (u64)r)
+/* the structure of utp message which is mapped to 16-byte SCSI CBW's CDB */
#pragma pack(1)
struct utp_msg {
u8 f0;
diff --git a/drivers/usb/host/ehci-arc.c b/drivers/usb/host/ehci-arc.c
index 21133fb8e47a..5cfcf169e7c7 100644
--- a/drivers/usb/host/ehci-arc.c
+++ b/drivers/usb/host/ehci-arc.c
@@ -23,9 +23,28 @@
#include <linux/fsl_devices.h>
#include <linux/usb/otg.h>
+#include "../core/usb.h"
#include "ehci-fsl.h"
#include <mach/fsl_usb.h>
+extern int usb_host_wakeup_irq(struct device *wkup_dev);
+extern void usb_host_set_wakeup(struct device *wkup_dev, bool para);
+static void fsl_usb_lowpower_mode(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ if (enable){
+ if (pdata->phy_lowpower_suspend)
+ pdata->phy_lowpower_suspend(true);
+ } else {
+ if (pdata->phy_lowpower_suspend)
+ pdata->phy_lowpower_suspend(false);
+ }
+}
+
+static void fsl_usb_clk_gate(struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ if (pdata->usb_clock_for_pm)
+ pdata->usb_clock_for_pm(enable);
+}
#undef EHCI_PROC_PTC
#ifdef EHCI_PROC_PTC /* /proc PORTSC:PTC support */
/*
@@ -90,8 +109,39 @@ static int ehci_testmode_init(struct ehci_hcd *ehci)
#endif /* /proc PORTSC:PTC support */
-/* configure so an HC device and id are always provided */
-/* always called with process context; sleeping is OK */
+/*
+ * This irq is used to open the hw access and let usb_hcd_irq process the usb event
+ * ehci_fsl_pre_irq will be called before usb_hcd_irq
+ */
+static irqreturn_t ehci_fsl_pre_irq(int irq, void *dev)
+{
+ struct platform_device *pdev = (struct platform_device *)dev;
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct fsl_usb2_platform_data *pdata;
+
+ pdata = hcd->self.controller->platform_data;
+
+ /* if it is an otg module and in b device mode, we need to do noting here */
+ if (ehci->transceiver && !ehci->transceiver->default_a)
+ return IRQ_NONE;
+
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ /* Need to open clk for accessing the register */
+ fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
+ /* if receive a remote wakeup interrrupt after suspend */
+ if (usb_host_wakeup_irq(hcd->self.controller)) {
+ printk("host wakeup event happens\n");
+ /* disable remote wake up irq */
+ usb_host_set_wakeup(hcd->self.controller, false);
+ fsl_usb_lowpower_mode(pdata, false);
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ }else {
+ fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
+ }
+ }
+ return IRQ_NONE;
+}
/**
* usb_hcd_fsl_probe - initialize FSL-based HCDs
@@ -182,10 +232,19 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver,
fsl_platform_set_host_mode(hcd);
hcd->power_budget = pdata->power_budget;
- retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ /*
+ * The ehci_fsl_pre_irq must be registered before usb_hcd_irq, in that case
+ * it can be called before usb_hcd_irq when irq occurs
+ */
+ retval = request_irq(irq, ehci_fsl_pre_irq, IRQF_SHARED,
+ "fsl ehci pre interrupt", (void *)pdev);
if (retval != 0)
goto err4;
+ retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ if (retval != 0)
+ goto err5;
+
fsl_platform_set_vbus_power(pdata, 1);
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
@@ -199,7 +258,7 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver,
if (!ehci->transceiver) {
printk(KERN_ERR "can't find transceiver\n");
retval = -ENODEV;
- goto err4;
+ goto err5;
}
retval = otg_set_host(ehci->transceiver, &ehci_to_hcd(ehci)->self);
@@ -216,7 +275,8 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver,
fsl_platform_set_ahb_burst(hcd);
ehci_testmode_init(hcd_to_ehci(hcd));
return retval;
-
+err5:
+ free_irq(irq, (void *)pdev);
err4:
iounmap(hcd->regs);
err3:
@@ -231,9 +291,6 @@ err1:
return retval;
}
-/* may be called without controller electrically present */
-/* may be called with controller, bus, and devices active */
-
/**
* usb_hcd_fsl_remove - shutdown processing for FSL-based HCDs
* @dev: USB Host Controller being removed
@@ -324,6 +381,59 @@ static int ehci_fsl_reinit(struct ehci_hcd *ehci)
return 0;
}
+static int ehci_fsl_bus_suspend(struct usb_hcd *hcd)
+{
+ int ret = 0;
+ struct fsl_usb2_platform_data *pdata;
+ pdata = hcd->self.controller->platform_data;
+ pr_debug("%s, %s\n", __func__, pdata->name);
+
+ /* the host is already at low power mode */
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ return 0;
+ }
+
+ pr_debug("%s, it is the host mode, %s\n", __func__, pdata->name);
+
+ ehci_bus_suspend(hcd);
+
+ if (pdata->platform_suspend)
+ pdata->platform_suspend(pdata);
+
+ usb_host_set_wakeup(hcd->self.controller, true);
+ fsl_usb_lowpower_mode(pdata, true);
+ fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+ return ret;
+}
+
+static int ehci_fsl_bus_resume(struct usb_hcd *hcd)
+{
+ int ret = 0;
+ struct fsl_usb2_platform_data *pdata;
+
+ pdata = hcd->self.controller->platform_data;
+ pr_debug("%s, %s\n", __func__, pdata->name);
+
+ /* if it is a remote wakeup, it will open clock and clear PHCD automatically */
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
+ usb_host_set_wakeup(hcd->self.controller, false);
+ fsl_usb_lowpower_mode(pdata, false);
+ }
+
+ if (pdata->platform_resume)
+ pdata->platform_resume(pdata);
+ ret = ehci_bus_resume(hcd);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+
/* called during probe() after chip reset completes */
static int ehci_fsl_setup(struct usb_hcd *hcd)
{
@@ -396,8 +506,8 @@ static const struct hc_driver ehci_fsl_hc_driver = {
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
+ .bus_suspend = ehci_fsl_bus_suspend,
+ .bus_resume = ehci_fsl_bus_resume,
.start_port_reset = ehci_start_port_reset,
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
@@ -438,13 +548,36 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev,
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- u32 tmp, port_status;
+ struct usb_device *roothub = hcd->self.root_hub;
+ u32 port_status;
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
- if (device_may_wakeup(&(pdev->dev))) {
- /* Need open clock for register access */
- if (pdata->usb_clock_for_pm)
- pdata->usb_clock_for_pm(true);
+ /* Only handles OTG mode switch event, system suspend event will be done in bus suspend */
+ if (pdev->dev.power.status == DPM_SUSPENDING){
+ pr_debug("%s, system pm event \n", __func__);
+ if (!device_may_wakeup(&(pdev->dev))){
+ /* Need open clock for register access */
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
+ fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
+ usb_host_set_wakeup(hcd->self.controller, false);
+ fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
+ }
+ return 0;
+ }
+ /* only the otg host can go here */
+ /* wait for all usb device on the hcd dettached */
+ while(roothub->children[0] != NULL)
+ msleep(1);
+ if ((pdata->operating_mode != FSL_USB2_MPH_HOST) && (!(hcd->state & HC_STATE_SUSPENDED)))
+ {
+ usb_lock_device(roothub);
+ usb_external_suspend_device(roothub, PMSG_USER_SUSPEND);
+ usb_unlock_device(roothub);
+ }
+
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
}
#ifdef DEBUG
@@ -457,27 +590,9 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev,
pdata->suspended, pdata->already_suspended, mode, tmp);
#endif
- /*
- * If the controller is already suspended, then this must be a
- * PM suspend. Remember this fact, so that we will leave the
- * controller suspended at PM resume time.
- */
- if (pdata->suspended) {
- pr_debug("%s: already suspended, leaving early\n", __func__);
- pdata->already_suspended = 1;
- goto err1;
- }
-
- pr_debug("%s: suspending...\n", __func__);
-
printk(KERN_INFO "USB Host suspended\n");
port_status = ehci_readl(ehci, &ehci->regs->port_status[0]);
- pdev->dev.power.power_state = PMSG_SUSPEND;
-
- /* ignore non-host interrupts */
- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
/* save EHCI registers */
pdata->pm_command = ehci_readl(ehci, &ehci->regs->command);
pdata->pm_command &= ~CMD_RUN;
@@ -496,25 +611,11 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev,
/* clear PHCD bit */
pdata->pm_portsc &= ~PORT_PHCD;
-
- pdata->suspended = 1;
-
- if (!device_may_wakeup(&(pdev->dev))) {
- /* clear PP to cut power to the port */
- tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
- tmp &= ~PORT_POWER;
- ehci_writel(ehci, tmp, &ehci->regs->port_status[0]);
- goto err1;
- }
-
- tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
-
- if (pdata->platform_suspend)
- pdata->platform_suspend(pdata);
-err1:
- if (device_may_wakeup(&(pdev->dev))) {
- if (pdata->usb_clock_for_pm)
- pdata->usb_clock_for_pm(false);
+ if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ //fsl_usb_lowpower_mode(pdata ,true);
+ //usb_host_set_wakeup(hcd->self.controller, true);
+ fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
}
return 0;
}
@@ -523,47 +624,35 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct usb_device *roothub = hcd->self.root_hub;
u32 tmp;
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
-
- pr_debug("%s('%s'): suspend=%d already_suspended=%d\n", __func__,
- pdata->name, pdata->suspended, pdata->already_suspended);
-
- /*
- * If the controller was already suspended at suspend time,
- * then don't resume it now.
- */
- if (pdata->already_suspended) {
- pr_debug("already suspended, leaving early\n");
- pdata->already_suspended = 0;
- return 0;
- }
-
- if (!pdata->suspended) {
- pr_debug("not suspended, leaving early\n");
+ /* Only handles OTG mode switch event */
+ if (pdev->dev.power.status == DPM_RESUMING){
+ pr_debug("%s, system pm event \n", __func__);
+ if (hcd->self.is_b_host) {
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
+ }
+ usb_host_set_wakeup(hcd->self.controller, true);
+
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
+ }
+ }
return 0;
}
-
- /* If hcd is resumed by non-usb wakeup events,
- * then usb clocks are still not open when come here */
- if (device_may_wakeup(&(pdev->dev))) {
- /* Need open clock for register access */
- if (pdata->usb_clock_for_pm)
- pdata->usb_clock_for_pm(true);
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
+ //usb_host_set_wakeup(hcd->self.controller, false);
+ //fsl_usb_lowpower_mode(pdata, false);
}
- tmp = ehci_readl(ehci, &ehci->regs->port_status[0]);
-
- pdata->suspended = 0;
-
- pr_debug("%s resuming...\n", __func__);
-
+ printk("USB Host resume ... %s\n", pdata->name);
/* set host mode */
fsl_platform_set_host_mode(hcd);
- if (pdata->platform_resume)
- pdata->platform_resume(pdata);
-
/* restore EHCI registers */
ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
@@ -575,32 +664,21 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev)
ehci_writel(ehci, pdata->pm_configured_flag,
&ehci->regs->configured_flag);
- /* set bit should be done by wakeup irq routine if may wakeup */
- if (!device_may_wakeup(&(pdev->dev)))
- set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- else
- while (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
- msleep(1);
-
- pdev->dev.power.power_state = PMSG_ON;
tmp = ehci_readl(ehci, &ehci->regs->command);
tmp |= CMD_RUN;
ehci_writel(ehci, tmp, &ehci->regs->command);
- usb_hcd_resume_root_hub(hcd);
-
- printk(KERN_INFO "USB Host resumed\n");
-
- if (device_may_wakeup(&(pdev->dev))) {
- if (pdata->usb_clock_for_pm)
- pdata->usb_clock_for_pm(false);
+ if ((hcd->state & HC_STATE_SUSPENDED)){
+ usb_lock_device(roothub);
+ usb_external_resume_device(roothub, PMSG_USER_RESUME);
+ usb_unlock_device(roothub);
}
+ printk(KERN_INFO "USB Host resume ok\n");
return 0;
}
-#endif /* CONFIG_USB_OTG */
-
+#endif
MODULE_ALIAS("platform:fsl-ehci");
static struct platform_driver ehci_fsl_driver = {
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index de459bbd1eb1..44ff32306362 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -112,6 +112,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
int port;
int mask;
+ printk("%s\n", __func__);
ehci_dbg(ehci, "suspend root hub\n");
if (time_before (jiffies, ehci->next_statechange))
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c
index b1454886fd7a..81a2985632b6 100644
--- a/drivers/usb/otg/fsl_otg.c
+++ b/drivers/usb/otg/fsl_otg.c
@@ -34,6 +34,7 @@
#include <linux/init.h>
#include <linux/reboot.h>
#include <linux/timer.h>
+#include <linux/jiffies.h>
#include <linux/list.h>
#include <linux/usb.h>
#include <linux/device.h>
@@ -41,6 +42,7 @@
#include <linux/usb/gadget.h>
#include <linux/workqueue.h>
#include <linux/time.h>
+#include <linux/usb/fsl_xcvr.h>
#include <linux/fsl_devices.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
@@ -60,6 +62,8 @@
#define DRIVER_DESC "Freescale USB OTG Driver"
#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
+#define TIMER_FREQ 1000 /* 100 ms*/
+#define IDLE_TIME 5000 /* 1000 ms */
MODULE_DESCRIPTION("Freescale USB OTG Transceiver Driver");
@@ -89,6 +93,13 @@ static struct fsl_otg_config fsl_otg_initdata = {
.otg_port = 1,
};
+/* the timer is used to monitor the otg loading, if idle for some times
+ * we will close the otg clk
+ */
+static unsigned long last_busy;
+static bool clk_stopped;
+static struct timer_list monitor_timer;
+
int write_ulpi(u8 addr, u8 data)
{
u32 temp;
@@ -136,17 +147,10 @@ void fsl_otg_dischrg_vbus(int on)
}
/* A-device driver vbus, controlled through PP bit in PORTSC */
-void fsl_otg_drv_vbus(int on)
+void fsl_otg_drv_vbus(struct fsl_usb2_platform_data *pdata, int on)
{
-/* if (on)
- usb_dr_regs->portsc =
- cpu_to_le32((le32_to_cpu(usb_dr_regs->portsc) &
- ~PORTSC_W1C_BITS) | PORTSC_PORT_POWER);
- else
- usb_dr_regs->portsc =
- cpu_to_le32(le32_to_cpu(usb_dr_regs->portsc) &
- ~PORTSC_W1C_BITS & ~PORTSC_PORT_POWER);
-*/
+ if (pdata->xcvr_ops && pdata->xcvr_ops->set_vbus_power)
+ pdata->xcvr_ops->set_vbus_power(pdata->xcvr_ops, pdata, on);
}
/*
@@ -395,6 +399,61 @@ int fsl_otg_tick_timer(void)
return expired;
}
+static void fsl_otg_clk_gate(bool on)
+{
+ struct device *dev = fsl_otg_dev->otg.dev;
+ struct fsl_usb2_platform_data *pdata;
+
+ if (dev) {
+ pdata = dev->platform_data;
+ if (pdata && pdata->usb_clock_for_pm)
+ pdata->usb_clock_for_pm(on);
+ }
+}
+
+static void fsl_otg_clk_ctl(void)
+{
+ if (clk_stopped){
+ fsl_otg_clk_gate(true);
+ clk_stopped = false;
+ }
+ last_busy = jiffies;
+}
+
+static void fsl_otg_loading_monitor(unsigned long data)
+{
+ unsigned long now = jiffies;
+ if (!clk_stopped){
+ if (time_after(now, last_busy + msecs_to_jiffies(IDLE_TIME))){
+ printk("otg is idle for some times,so we close the clock %x\n", le32_to_cpu(usb_dr_regs->otgsc));
+ clk_stopped = true;
+ fsl_otg_clk_gate(false);
+ printk("close otg clk ok\n");
+ }
+ }
+ mod_timer(&monitor_timer, jiffies + msecs_to_jiffies(TIMER_FREQ));
+}
+
+/**
+ * Enable vbus interrupt
+ * The otg cares USB_ID interrupt
+ * The device cares B Sesstion Valid
+ */
+static void b_session_irq_enable(bool enable)
+{
+ int osc = le32_to_cpu(usb_dr_regs->otgsc);
+ /* The other interrupts' status should not be cleared */
+ osc &= ~(OTGSC_INTSTS_USB_ID | OTGSC_INTSTS_A_VBUS_VALID
+ | OTGSC_INTSTS_A_SESSION_VALID | OTGSC_INTSTS_B_SESSION_VALID);
+ osc |= OTGSC_INTSTS_B_SESSION_VALID;
+
+ if (enable)
+ osc |= OTGSC_INTR_B_SESSION_VALID_EN;
+ else
+ osc &= ~OTGSC_INTR_B_SESSION_VALID_EN;
+ usb_dr_regs->otgsc = cpu_to_le32(osc);
+}
+
/* Reset controller, not reset the bus */
void otg_reset_controller(void)
{
@@ -438,7 +497,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on)
retval = host_pdrv->resume(host_pdev);
if (fsm->id) {
/* default-b */
- fsl_otg_drv_vbus(1);
+ fsl_otg_drv_vbus(dev->platform_data, 1);
/* Workaround: b_host can't driver
* vbus, but PP in PORTSC needs to
* be 1 for host to work.
@@ -463,7 +522,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on)
otg_suspend_state);
if (fsm->id)
/* default-b */
- fsl_otg_drv_vbus(0);
+ fsl_otg_drv_vbus(dev->platform_data, 0);
}
otg_dev->host_working = 0;
}
@@ -481,7 +540,6 @@ int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
struct device *dev;
struct platform_driver *gadget_pdrv;
struct platform_device *gadget_pdev;
-
if (!xceiv->gadget || !xceiv->gadget->dev.parent)
return -ENODEV;
@@ -517,7 +575,6 @@ static int fsl_otg_set_host(struct otg_transceiver *otg_p, struct usb_bus *host)
if (host) {
VDBG("host off......\n");
-
otg_p->host->otg_port = fsl_otg_initdata.otg_port;
otg_p->host->is_b_host = otg_dev->fsm.id;
/* must leave time for khubd to finish its thing
@@ -634,11 +691,29 @@ static void fsl_otg_event(struct work_struct *work)
{
struct fsl_otg *og = container_of(work, struct fsl_otg, otg_event.work);
struct otg_fsm *fsm = &og->fsm;
+ struct otg_transceiver *otg = &og->otg;
+
+ otg->default_a = (fsm->id == 0);
+ /* clear conn information */
+ if (fsm->id)
+ fsm->b_conn = 0;
+ else
+ fsm->a_conn = 0;
+
+ if (otg->host)
+ otg->host->is_b_host = fsm->id;
+ if (otg->gadget)
+ otg->gadget->is_a_peripheral = !fsm->id;
if (fsm->id) { /* switch to gadget */
+ b_session_irq_enable(true);
fsl_otg_start_host(fsm, 0);
otg_drv_vbus(fsm, 0);
fsl_otg_start_gadget(fsm, 1);
+ }else { /* switch to host */
+ fsl_otg_start_gadget(fsm, 0);
+ otg_drv_vbus(fsm, 1);
+ fsl_otg_start_host(fsm, 1);
}
}
@@ -678,12 +753,13 @@ irqreturn_t fsl_otg_isr_gpio(int irq, void *dev_id)
struct otg_fsm *fsm;
struct fsl_usb2_platform_data *pdata =
(struct fsl_usb2_platform_data *)dev_id;
- struct fsl_otg *p_otg;
+ struct fsl_otg *f_otg;
struct otg_transceiver *otg_trans = otg_get_transceiver();
- p_otg = container_of(otg_trans, struct fsl_otg, otg);
- fsm = &p_otg->fsm;
int value;
+ f_otg = container_of(otg_trans, struct fsl_otg, otg);
+ fsm = &f_otg->fsm;
+ fsl_otg_clk_ctl();
if (pdata->id_gpio == 0)
return IRQ_NONE;
@@ -695,35 +771,25 @@ irqreturn_t fsl_otg_isr_gpio(int irq, void *dev_id)
set_irq_type(gpio_to_irq(pdata->id_gpio), IRQ_TYPE_LEVEL_HIGH);
- if (value == p_otg->fsm.id)
+ if (value == f_otg->fsm.id)
return IRQ_HANDLED;
- p_otg->fsm.id = value;
-
- otg_trans->default_a = (fsm->id == 0);
- /* clear conn information */
- if (fsm->id)
- fsm->b_conn = 0;
- else
- fsm->a_conn = 0;
-
- if (otg_trans->host)
- otg_trans->host->is_b_host = fsm->id;
- if (otg_trans->gadget)
- otg_trans->gadget->is_a_peripheral = !fsm->id;
-
- VDBG("ID int (ID is %d)\n", fsm->id);
- if (fsm->id) { /* switch to gadget */
- schedule_delayed_work(&p_otg->otg_event, 100);
+ f_otg->fsm.id = value;
- } else { /* switch to host */
- cancel_delayed_work(&p_otg->otg_event);
- fsl_otg_start_gadget(fsm, 0);
- otg_drv_vbus(fsm, 1);
- fsl_otg_start_host(fsm, 1);
+ cancel_delayed_work(&f_otg->otg_event);
+ schedule_delayed_work(&f_otg->otg_event, msecs_to_jiffies(10));
+ /* if host mode, we should clear B_SESSION_VLD event and disable
+ * B_SESSION_VLD irq
+ */
+ if (!f_otg->fsm.id) {
+ b_session_irq_enable(false);
+ }else {
+ //b_session_irq_enable(true);
}
+
return IRQ_HANDLED;
}
+
/* Interrupt handler. OTG/host/peripheral share the same int line.
* OTG driver clears OTGSC interrupts and leaves USB interrupts
* intact. It needs to have knowledge of some USB interrupts
@@ -731,60 +797,70 @@ irqreturn_t fsl_otg_isr_gpio(int irq, void *dev_id)
*/
irqreturn_t fsl_otg_isr(int irq, void *dev_id)
{
- struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm;
- struct otg_transceiver *otg = &((struct fsl_otg *)dev_id)->otg;
+ struct fsl_otg *fotg = (struct fsl_otg *)dev_id;
+ struct otg_transceiver *otg = &fotg->otg;
u32 otg_int_src, otg_sc;
+ irqreturn_t ret = IRQ_NONE;
+ fsl_otg_clk_ctl();
otg_sc = le32_to_cpu(usb_dr_regs->otgsc);
otg_int_src = otg_sc & OTGSC_INTSTS_MASK & (otg_sc >> 8);
- /* Only clear otg interrupts */
- usb_dr_regs->otgsc |= cpu_to_le32(otg_sc & OTGSC_INTSTS_MASK);
+ /* Only clear otg interrupts, expect B_SESSION_VALID,
+ * Leave it to be handled by arcotg_udc */
+ usb_dr_regs->otgsc = ((usb_dr_regs->otgsc | cpu_to_le32(otg_sc & OTGSC_INTSTS_MASK))&
+ (~OTGSC_INTSTS_B_SESSION_VALID));
/*FIXME: ID change not generate when init to 0 */
- fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0;
- otg->default_a = (fsm->id == 0);
+ fotg->fsm.id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0;
+ otg->default_a = (fotg->fsm.id == 0);
/* process OTG interrupts */
if (otg_int_src) {
if (otg_int_src & OTGSC_INTSTS_USB_ID) {
- fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0;
- otg->default_a = (fsm->id == 0);
- /* clear conn information */
- if (fsm->id)
- fsm->b_conn = 0;
- else
- fsm->a_conn = 0;
-
- if (otg->host)
- otg->host->is_b_host = fsm->id;
- if (otg->gadget)
- otg->gadget->is_a_peripheral = !fsm->id;
- VDBG("ID int (ID is %d)\n", fsm->id);
-
- if (fsm->id) { /* switch to gadget */
- schedule_delayed_work(&((struct fsl_otg *)
- dev_id)->otg_event,
- 100);
- } else { /* switch to host */
- cancel_delayed_work(&
- ((struct fsl_otg *)dev_id)->
- otg_event);
- fsl_otg_start_gadget(fsm, 0);
- otg_drv_vbus(fsm, 1);
- fsl_otg_start_host(fsm, 1);
+ fotg->fsm.id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0;
+
+ printk("ID int (ID is %d)\n", fotg->fsm.id);
+
+ cancel_delayed_work(&fotg->otg_event);
+ schedule_delayed_work(&fotg->otg_event, msecs_to_jiffies(10));
+ /* if host mode, we should clear B_SESSION_VLD event and disable
+ * B_SESSION_VLD irq
+ */
+ if (!fotg->fsm.id) {
+ b_session_irq_enable(false);
+ }else {
+ //b_session_irq_enable(true);
}
-
- return IRQ_HANDLED;
+ ret = IRQ_HANDLED;
}
}
- return IRQ_NONE;
+ return ret;
+}
+
+static void fsl_otg_fsm_drv_vbus(int on)
+{
+ struct otg_fsm *fsm = &(fsl_otg_dev->fsm);
+ struct otg_transceiver *xceiv = fsm->transceiver;
+
+ struct device *dev;
+ /*
+ * The host is assigned at otg_set_host
+ */
+ if (!xceiv->host)
+ return;
+ /*
+ * The dev is assigned at usb_create_hcd which is called earlier
+ * than otg_set_host at host driver's probe
+ */
+ dev = xceiv->host->controller;
+ fsl_otg_drv_vbus(dev->platform_data, on);
}
static struct otg_fsm_ops fsl_otg_ops = {
.chrg_vbus = fsl_otg_chrg_vbus,
- .drv_vbus = fsl_otg_drv_vbus,
+ .drv_vbus = fsl_otg_fsm_drv_vbus,
.loc_conn = fsl_otg_loc_conn,
.loc_sof = fsl_otg_loc_sof,
.start_pulse = fsl_otg_start_pulse,
@@ -837,6 +913,7 @@ static int fsl_otg_conf(struct platform_device *pdev)
fsl_otg_tc->otg.set_power = fsl_otg_set_power;
fsl_otg_tc->otg.start_hnp = fsl_otg_start_hnp;
fsl_otg_tc->otg.start_srp = fsl_otg_start_srp;
+ fsl_otg_tc->otg.dev = &pdev->dev;
fsl_otg_dev = fsl_otg_tc;
@@ -903,6 +980,8 @@ int usb_otg_start(struct platform_device *pdev)
if (pdata->platform_init && pdata->platform_init(pdev) != 0)
return -EINVAL;
+ clk_stopped = false; /* platform_init will open the otg clk */
+
/* stop the controller */
temp = readl(&p_otg->dr_mem_map->usbcmd);
temp &= ~USB_CMD_RUN_STOP;
@@ -1229,6 +1308,10 @@ static int __init fsl_otg_probe(struct platform_device *pdev)
return -EIO;
}
+ last_busy = jiffies;
+ setup_timer(&monitor_timer, fsl_otg_loading_monitor, (unsigned long)pdev);
+ mod_timer(&monitor_timer, jiffies + msecs_to_jiffies(TIMER_FREQ));
+
create_proc_file();
return status;
}
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 34e4e7995169..9c4739c8b19c 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -35,6 +35,11 @@ EXPORT_SYMBOL_GPL(fb_mode_option);
*/
static const struct fb_videomode modedb[] = {
+ {
+ /* 800x480 @ 60 Hz, 31.5 kHz hsync */
+ "LQ070Y3DG3B", 60, 800, 480, 44000, 0, 50, 25, 10, 128, 10,
+ FB_SYNC_EXT,FB_VMODE_NONINTERLACED
+ },
{
/* 640x400 @ 70 Hz, 31.5 kHz hsync */
NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2,
diff --git a/drivers/video/mxc/Kconfig b/drivers/video/mxc/Kconfig
index 268879626fc2..42f990ac3499 100644
--- a/drivers/video/mxc/Kconfig
+++ b/drivers/video/mxc/Kconfig
@@ -26,12 +26,21 @@ config FB_MXC_EPSON_VGA_SYNC_PANEL
config FB_MXC_TVOUT_TVE
tristate "MXC TVE TV Out Encoder"
- depends on FB_MXC_SYNC_PANEL
- depends on MXC_IPU_V3
+ depends on FB_MXC_SYNC_PANEL
+ depends on MXC_IPU_V3
+
+config FB_MXC_LDB
+ tristate "MXC LDB"
+ depends on FB_MXC_SYNC_PANEL
+ depends on MXC_IPU_V3
config FB_MXC_CLAA_WVGA_SYNC_PANEL
+ depends on FB_MXC_SYNC_PANEL
+ tristate "CLAA WVGA Panel"
+
+config FB_MXC_SII9022
depends on FB_MXC_SYNC_PANEL
- tristate "CLAA WVGA Panel"
+ tristate "Si Image SII9022 DVI/HDMI Interface Chip"
config FB_MXC_CH7026
depends on FB_MXC_SYNC_PANEL
@@ -43,12 +52,21 @@ config FB_MXC_TVOUT_CH7024
config FB_MXC_LOW_PWR_DISPLAY
bool "Low Power Display Refresh Mode"
- depends on FB_MXC_SYNC_PANEL && MXC_FB_IRAM
- default y
+ depends on FB_MXC_SYNC_PANEL && MXC_FB_IRAM
+ default y
+
+config VIDEO_AD9389
+ tristate "Analog Devices AD9389/AD9889 digital video encoders"
+ depends on I2C && FB_MXC_SYNC_PANEL
+ ---help---
+ Support for the AD9389/AD9889 HDMI/DVI Video transmiter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad9389.
config FB_MXC_INTERNAL_MEM
- bool "Framebuffer in Internal RAM"
- depends on FB_MXC_SYNC_PANEL && MXC_FB_IRAM
+ bool "Framebuffer in Internal RAM"
+ depends on FB_MXC_SYNC_PANEL && MXC_FB_IRAM
default y
config FB_MXC_ASYNC_PANEL
@@ -66,9 +84,24 @@ config FB_MXC_EPSON_PANEL
endmenu
+config FB_MXC_EINK_PANEL
+ depends on FB_MXC
+ depends on DMA_ENGINE
+ select FB_DEFERRED_IO
+ tristate "E-Ink Panel Framebuffer"
+
+config FB_MXC_EINK_AUTO_UPDATE_MODE
+ bool "E-Ink Auto-update Mode Support"
+ default n
+ depends on FB_MXC_EINK_PANEL
+
+config FB_MXC_ELCDIF_FB
+ depends on FB && ARCH_MXC
+ tristate "Support MXC ELCDIF framebuffer"
+
choice
- prompt "Async Panel Interface Type"
- depends on FB_MXC_ASYNC_PANEL && FB_MXC
+ prompt "Async Panel Interface Type"
+ depends on FB_MXC_ASYNC_PANEL && FB_MXC
default FB_MXC_ASYNC_PANEL_IFC_16_BIT
config FB_MXC_ASYNC_PANEL_IFC_8_BIT
diff --git a/drivers/video/mxc/Makefile b/drivers/video/mxc/Makefile
index d2454aac2604..d823ab29f030 100644
--- a/drivers/video/mxc/Makefile
+++ b/drivers/video/mxc/Makefile
@@ -18,5 +18,7 @@ obj-$(CONFIG_FB_MXC_EPSON_VGA_SYNC_PANEL) += mxcfb_epson_vga.o
obj-$(CONFIG_FB_MXC_CLAA_WVGA_SYNC_PANEL) += mxcfb_claa_wvga.o
obj-$(CONFIG_FB_MXC_TVOUT_CH7024) += ch7024.o
obj-$(CONFIG_FB_MXC_TVOUT_TVE) += tve.o
-obj-$(CONFIG_FB_MXC_CH7026) += mxcfb_ch7026.o
-#obj-$(CONFIG_FB_MODE_HELPERS) += mxc_edid.o
+obj-$(CONFIG_FB_MXC_CH7026) += mxcfb_ch7026.o
+#obj-$(CONFIG_FB_MODE_HELPERS) += mxc_edid.o
+obj-$(CONFIG_VIDEO_AD9389) += ad9389.o
+obj-$(CONFIG_FB_MXC_SII9022) += mxcfb_sii9022.o
diff --git a/drivers/video/mxc/ccwmx51_display.c b/drivers/video/mxc/ccwmx51_display.c
index 70a5b25f3fe9..212f59e919e4 100755
--- a/drivers/video/mxc/ccwmx51_display.c
+++ b/drivers/video/mxc/ccwmx51_display.c
@@ -22,23 +22,37 @@
#include <mach/hardware.h>
#include <mach/mxc.h>
+#define MAX_DISPLAYS 2
+#define DISP0_ID "DISP3 BG"
+#define DISP1_ID "DISP3 BG - DI1"
+
static void lcd_poweron(struct ccwmx51_lcd_pdata *plat);
static void lcd_poweroff(struct ccwmx51_lcd_pdata *plat);
-static struct platform_device *plcd_dev;
+static struct platform_device *plcd_dev[MAX_DISPLAYS] = {NULL, NULL};
+
+static int lcd_get_index(struct fb_info *info)
+{
+ if (!strcmp(info->fix.id, DISP0_ID))
+ return 0;
+ else if (!strcmp(info->fix.id, DISP1_ID))
+ return 1;
+ return -1;
+}
static void lcd_init_fb(struct fb_info *info)
{
- struct ccwmx51_lcd_pdata *plat = plcd_dev->dev.platform_data;
struct fb_var_screeninfo var;
+ struct ccwmx51_lcd_pdata *plat;
+ int i = lcd_get_index(info);
- memset(&var, 0, sizeof(var));
+ if (i < 0)
+ return;
+ plat = plcd_dev[i]->dev.platform_data;
+ memset(&var, 0, sizeof(var));
fb_videomode_to_var(&var, plat->fb_pdata.mode);
-
var.activate = FB_ACTIVATE_ALL;
- var.yres_virtual = var.yres;
-
acquire_console_sem();
info->flags |= FBINFO_MISC_USEREVENT;
fb_set_var(info, &var);
@@ -74,18 +88,37 @@ static struct notifier_block nb = {
static int __devinit lcd_sync_probe(struct platform_device *pdev)
{
struct ccwmx51_lcd_pdata *plat = pdev->dev.platform_data;
+ int i;
+
+ if (!plat)
+ return -ENODEV;
- if (!plat)
- return -ENODEV;
+ if (plat->vif < 0 || plat->vif > (MAX_DISPLAYS - 1))
+ return -EINVAL;
- if (plat->reset)
- plat->reset();
+ if (plat->init)
+ plat->init(plat->vif);
- plcd_dev = pdev;
- lcd_init_fb(registered_fb[plat->vif]);
- fb_show_logo(registered_fb[plat->vif], 0);
- fb_register_client(&nb);
+ plcd_dev[plat->vif] = pdev;
+ for (i = 0; i < num_registered_fb; i++) {
+ if ((!strcmp(registered_fb[i]->fix.id, DISP0_ID) && plat->vif == 0) ||
+ (!strcmp(registered_fb[i]->fix.id, DISP1_ID) && plat->vif == 1)) {
+ lcd_init_fb(registered_fb[i]);
+ /* Clear the screen */
+ memset((char *)registered_fb[i]->screen_base, 0,
+ registered_fb[i]->fix.smem_len);
+ fb_show_logo(registered_fb[i], 0);
+ }
+ }
+
+ /**
+ * Register the block notifier only once. The device being notified can be
+ * retrieved from the received event. There are some issues when the same
+ * notifier is registered multiple times.
+ */
+ if (plcd_dev[0] == NULL && plcd_dev[1] == NULL)
+ fb_register_client(&nb);
lcd_poweron(plat);
return 0;
@@ -95,9 +128,14 @@ static int __devexit lcd_sync_remove(struct platform_device *pdev)
{
struct ccwmx51_lcd_pdata *plat = pdev->dev.platform_data;
- fb_unregister_client(&nb);
lcd_poweroff(plat);
- plcd_dev = NULL;
+ if (plat->deinit)
+ plat->deinit(plat->vif);
+
+ plcd_dev[plat->vif] = NULL;
+
+ if (plcd_dev[0] == NULL && plcd_dev[1] == NULL)
+ fb_unregister_client(&nb);
return 0;
}
@@ -129,14 +167,14 @@ static struct platform_driver lcd_driver = {
static void lcd_poweron(struct ccwmx51_lcd_pdata *plat)
{
- if (plat && plat->bl_enable)
- plat->bl_enable(0);
+ if (plat && plat->bl_enable)
+ plat->bl_enable(1, plat->vif);
}
static void lcd_poweroff(struct ccwmx51_lcd_pdata *plat)
{
- if (plat && plat->bl_enable)
- plat->bl_enable(1);
+ if (plat && plat->bl_enable)
+ plat->bl_enable(0, plat->vif);
}
static int __init lcd_sync_init(void)
diff --git a/drivers/video/mxc/mxc_ipuv3_fb.c b/drivers/video/mxc/mxc_ipuv3_fb.c
index 76c6d523c291..cc48e62637ca 100644
--- a/drivers/video/mxc/mxc_ipuv3_fb.c
+++ b/drivers/video/mxc/mxc_ipuv3_fb.c
@@ -22,7 +22,6 @@
*
* @ingroup Framebuffer
*/
-
/*!
* Include files
*/
@@ -44,9 +43,13 @@
#include <linux/io.h>
#include <linux/ipu.h>
#include <linux/mxcfb.h>
+#include <linux/earlysuspend.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
+#include <linux/suspend.h>
+
+static int vt_switch;
/*
* Driver name
@@ -56,11 +59,14 @@
* Structure containing the MXC specific framebuffer information.
*/
struct mxcfb_info {
+ char *fb_mode_str;
+ int default_bpp;
int cur_blank;
int next_blank;
ipu_channel_t ipu_ch;
int ipu_di;
u32 ipu_di_pix_fmt;
+ bool ipu_ext_clk;
bool overlay;
bool alpha_chan_en;
dma_addr_t alpha_phy_addr0;
@@ -74,6 +80,8 @@ struct mxcfb_info {
u32 pseudo_palette[16];
+ bool wait4vsync;
+ uint32_t waitcnt;
struct semaphore flip_sem;
struct semaphore alpha_flip_sem;
struct completion vsync_complete;
@@ -93,12 +101,10 @@ enum {
BOTH_OFF
};
-static char *fb_mode;
-static unsigned long default_bpp = 16;
+#define FB_DEVICE_NUM 3
static bool g_dp_in_use;
LIST_HEAD(fb_alloc_list);
-static struct fb_info *mxcfb_info[3];
-static int ext_clk_used;
+static struct fb_info *mxcfb_info[FB_DEVICE_NUM];
static uint32_t bpp_to_pixfmt(struct fb_info *fbi)
{
@@ -125,6 +131,7 @@ static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id);
static int mxcfb_blank(int blank, struct fb_info *info);
static int mxcfb_map_video_memory(struct fb_info *fbi);
static int mxcfb_unmap_video_memory(struct fb_info *fbi);
+static int mxcfb_option_setup(struct fb_info *info, char *options);
/*
* Set fixed framebuffer parameters based on variable settings.
@@ -165,30 +172,42 @@ static int _setup_disp_channel1(struct fb_info *fbi)
for (i = 0; i < num_registered_fb; i++) {
mxc_fbi_tmp = (struct mxcfb_info *)
- (registered_fb[i]->par);
+ (registered_fb[i]->par);
if (mxc_fbi_tmp->ipu_ch == MEM_BG_SYNC) {
- fbi->var.vmode =
- registered_fb[i]->var.vmode;
+ fbi->var.vmode = registered_fb[i]->var.vmode;
mxc_fbi->ipu_di_pix_fmt =
- mxc_fbi_tmp->ipu_di_pix_fmt;
+ mxc_fbi_tmp->ipu_di_pix_fmt;
break;
}
}
}
- if (fbi->var.vmode & FB_VMODE_INTERLACED) {
- params.mem_dp_bg_sync.interlaced = true;
- params.mem_dp_bg_sync.out_pixel_fmt =
- IPU_PIX_FMT_YUV444;
+ if (mxc_fbi->ipu_ch == MEM_DC_SYNC) {
+ if (fbi->var.vmode & FB_VMODE_INTERLACED) {
+ params.mem_dc_sync.interlaced = true;
+ params.mem_dc_sync.out_pixel_fmt =
+ IPU_PIX_FMT_YUV444;
+ } else {
+ if (mxc_fbi->ipu_di_pix_fmt)
+ params.mem_dc_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
+ else
+ params.mem_dc_sync.out_pixel_fmt = IPU_PIX_FMT_RGB666;
+ }
+ params.mem_dc_sync.in_pixel_fmt = bpp_to_pixfmt(fbi);
} else {
- if (mxc_fbi->ipu_di_pix_fmt)
- params.mem_dp_bg_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
- else
- params.mem_dp_bg_sync.out_pixel_fmt = IPU_PIX_FMT_RGB666;
+ if (fbi->var.vmode & FB_VMODE_INTERLACED) {
+ params.mem_dp_bg_sync.interlaced = true;
+ params.mem_dp_bg_sync.out_pixel_fmt =
+ IPU_PIX_FMT_YUV444;
+ } else {
+ if (mxc_fbi->ipu_di_pix_fmt)
+ params.mem_dp_bg_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
+ else
+ params.mem_dp_bg_sync.out_pixel_fmt = IPU_PIX_FMT_RGB666;
+ }
+ params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi);
+ if (mxc_fbi->alpha_chan_en)
+ params.mem_dp_bg_sync.alpha_chan_en = true;
}
- params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi);
- if (mxc_fbi->alpha_chan_en)
- params.mem_dp_bg_sync.alpha_chan_en = true;
-
ipu_init_channel(mxc_fbi->ipu_ch, &params);
return 0;
@@ -201,10 +220,12 @@ static int _setup_disp_channel2(struct fb_info *fbi)
int fb_stride;
switch (bpp_to_pixfmt(fbi)) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YVU420P:
+ case IPU_PIX_FMT_NV12:
+ case IPU_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YVU422P:
+ case IPU_PIX_FMT_YUV420P:
fb_stride = fbi->var.xres_virtual;
break;
default:
@@ -212,7 +233,7 @@ static int _setup_disp_channel2(struct fb_info *fbi)
}
mxc_fbi->cur_ipu_buf = 1;
- sema_init(&mxc_fbi->flip_sem, 1);
+ sema_init(&mxc_fbi->flip_sem, 0);
if (mxc_fbi->alpha_chan_en) {
mxc_fbi->cur_ipu_alpha_buf = 1;
sema_init(&mxc_fbi->alpha_flip_sem, 1);
@@ -226,8 +247,7 @@ static int _setup_disp_channel2(struct fb_info *fbi)
IPU_ROTATE_NONE,
fbi->fix.smem_start +
(fbi->fix.line_length * fbi->var.yres),
- fbi->fix.smem_start,
- 0, 0);
+ fbi->fix.smem_start, 0, 0);
if (retval) {
dev_err(fbi->device,
"ipu_init_channel_buffer error %d\n", retval);
@@ -297,38 +317,47 @@ static int mxcfb_set_par(struct fb_info *fbi)
mxc_fbi->alpha_phy_addr1);
mxc_fbi->alpha_virt_addr0 =
- dma_alloc_coherent(fbi->device,
- alpha_mem_len,
- &mxc_fbi->alpha_phy_addr0,
- GFP_DMA | GFP_KERNEL);
+ dma_alloc_coherent(fbi->device,
+ alpha_mem_len,
+ &mxc_fbi->alpha_phy_addr0,
+ GFP_DMA | GFP_KERNEL);
mxc_fbi->alpha_virt_addr1 =
- dma_alloc_coherent(fbi->device,
- alpha_mem_len,
- &mxc_fbi->alpha_phy_addr1,
- GFP_DMA | GFP_KERNEL);
+ dma_alloc_coherent(fbi->device,
+ alpha_mem_len,
+ &mxc_fbi->alpha_phy_addr1,
+ GFP_DMA | GFP_KERNEL);
if (mxc_fbi->alpha_virt_addr0 == NULL ||
mxc_fbi->alpha_virt_addr1 == NULL) {
dev_err(fbi->device, "mxcfb: dma alloc for"
" alpha buffer failed.\n");
if (mxc_fbi->alpha_virt_addr0)
dma_free_coherent(fbi->device,
- mxc_fbi->alpha_mem_len,
- mxc_fbi->alpha_virt_addr0,
- mxc_fbi->alpha_phy_addr0);
+ mxc_fbi->
+ alpha_mem_len,
+ mxc_fbi->
+ alpha_virt_addr0,
+ mxc_fbi->
+ alpha_phy_addr0);
if (mxc_fbi->alpha_virt_addr1)
dma_free_coherent(fbi->device,
- mxc_fbi->alpha_mem_len,
- mxc_fbi->alpha_virt_addr1,
- mxc_fbi->alpha_phy_addr1);
+ mxc_fbi->
+ alpha_mem_len,
+ mxc_fbi->
+ alpha_virt_addr1,
+ mxc_fbi->
+ alpha_phy_addr1);
return -ENOMEM;
}
mxc_fbi->alpha_mem_len = alpha_mem_len;
}
}
+#if !(defined(CONFIG_CCWMX51_DISP0) && defined(CONFIG_CCWMX51_DISP1))
+ /* FIXME this lines of code doesnt allow to run the dual head... */
if (mxc_fbi->next_blank != FB_BLANK_UNBLANK)
return retval;
+#endif
_setup_disp_channel1(fbi);
@@ -345,9 +374,9 @@ static int mxcfb_set_par(struct fb_info *fbi)
else
out_pixel_fmt = IPU_PIX_FMT_RGB666;
}
- if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
+ if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
sig_cfg.odd_field_first = true;
- if ((fbi->var.sync & FB_SYNC_EXT) || ext_clk_used)
+ if ((fbi->var.sync & FB_SYNC_EXT) || mxc_fbi->ipu_ext_clk)
sig_cfg.ext_clk = true;
if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
sig_cfg.Hsync_pol = true;
@@ -453,8 +482,7 @@ static int swap_channels(struct fb_info *fbi)
ch_to = MEM_BG_SYNC;
for (i = 0; i < num_registered_fb; i++) {
- mxc_fbi_to =
- (struct mxcfb_info *)mxcfb_info[i]->par;
+ mxc_fbi_to = (struct mxcfb_info *)mxcfb_info[i]->par;
if (mxc_fbi_to->ipu_ch == ch_to) {
fbi_to = mxcfb_info[i];
break;
@@ -519,14 +547,14 @@ static int swap_channels(struct fb_info *fbi)
}
if (ipu_request_irq(mxc_fbi_from->ipu_ch_irq, mxcfb_irq_handler, 0,
- MXCFB_NAME, fbi) != 0) {
+ MXCFB_NAME, fbi) != 0) {
dev_err(fbi->device, "Error registering irq %d\n",
mxc_fbi_from->ipu_ch_irq);
return -EBUSY;
}
ipu_disable_irq(mxc_fbi_from->ipu_ch_irq);
if (ipu_request_irq(mxc_fbi_to->ipu_ch_irq, mxcfb_irq_handler, 0,
- MXCFB_NAME, fbi_to) != 0) {
+ MXCFB_NAME, fbi_to) != 0) {
dev_err(fbi_to->device, "Error registering irq %d\n",
mxc_fbi_to->ipu_ch_irq);
return -EBUSY;
@@ -545,17 +573,48 @@ static int swap_channels(struct fb_info *fbi)
*/
static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par;
u32 vtotal;
u32 htotal;
+ /* fg should not bigger than bg */
+ if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
+ struct fb_info *fbi_tmp;
+ struct mxcfb_info *mxc_fbi_tmp;
+ int i, bg_xres, bg_yres;
+ int16_t pos_x, pos_y;
+
+ bg_xres = var->xres;
+ bg_yres = var->yres;
+
+ for (i = 0; i < num_registered_fb; i++) {
+ fbi_tmp = registered_fb[i];
+ mxc_fbi_tmp = (struct mxcfb_info *)
+ (fbi_tmp->par);
+ if (mxc_fbi_tmp->ipu_ch == MEM_BG_SYNC) {
+ bg_xres = fbi_tmp->var.xres;
+ bg_yres = fbi_tmp->var.yres;
+ break;
+ }
+ }
+
+ ipu_disp_get_window_pos(mxc_fbi->ipu_ch, &pos_x, &pos_y);
+
+ if ((var->xres + pos_x) > bg_xres)
+ var->xres = bg_xres - pos_x;
+ if ((var->yres + pos_y) > bg_yres)
+ var->yres = bg_yres - pos_y;
+ }
+
if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres;
if (var->yres_virtual < var->yres)
var->yres_virtual = var->yres;
if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
- (var->bits_per_pixel != 16) && (var->bits_per_pixel != 8))
- var->bits_per_pixel = default_bpp;
+ (var->bits_per_pixel != 16) && (var->bits_per_pixel != 12) &&
+ (var->bits_per_pixel != 8))
+ var->bits_per_pixel = mxc_fbi->default_bpp;
switch (var->bits_per_pixel) {
case 8:
@@ -723,7 +782,7 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
}
if (ipu_disp_set_global_alpha(mxc_fbi->ipu_ch,
- (bool)ga.enable,
+ (bool) ga.enable,
ga.alpha)) {
retval = -EINVAL;
break;
@@ -750,7 +809,7 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
}
if (ipu_disp_set_global_alpha(mxc_fbi->ipu_ch,
- !(bool)la.enable, 0)) {
+ !(bool) la.enable, 0)) {
retval = -EINVAL;
break;
}
@@ -765,8 +824,11 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
for (i = 0; i < num_registered_fb; i++) {
char *idstr = registered_fb[i]->fix.id;
- if (strcmp(idstr, video_plane_idstr) == 0) {
- ((struct mxcfb_info *)(registered_fb[i]->par))->alpha_chan_en = false;
+ if (strcmp(idstr, video_plane_idstr) ==
+ 0) {
+ ((struct mxcfb_info
+ *)(registered_fb[i]->par))->
+ alpha_chan_en = false;
break;
}
}
@@ -794,8 +856,8 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
uint32_t ipu_alp_ch_irq;
if (!(((mxc_fbi->ipu_ch == MEM_FG_SYNC) ||
- (mxc_fbi->ipu_ch == MEM_BG_SYNC)) &&
- (mxc_fbi->alpha_chan_en))) {
+ (mxc_fbi->ipu_ch == MEM_BG_SYNC)) &&
+ (mxc_fbi->alpha_chan_en))) {
dev_err(fbi->device,
"Should use background or overlay "
"framebuffer to set the alpha buffer "
@@ -822,11 +884,10 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
down(&mxc_fbi->alpha_flip_sem);
mxc_fbi->cur_ipu_alpha_buf =
- !mxc_fbi->cur_ipu_alpha_buf;
+ !mxc_fbi->cur_ipu_alpha_buf;
if (ipu_update_channel_buffer(mxc_fbi->ipu_ch,
IPU_ALPHA_IN_BUFFER,
- mxc_fbi->
- cur_ipu_alpha_buf,
+ mxc_fbi->cur_ipu_alpha_buf,
base) == 0) {
ipu_select_buffer(mxc_fbi->ipu_ch,
IPU_ALPHA_IN_BUFFER,
@@ -864,9 +925,9 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
}
retval = ipu_disp_set_gamma_correction(mxc_fbi->ipu_ch,
- gamma.enable,
- gamma.constk,
- gamma.slopek);
+ gamma.enable,
+ gamma.constk,
+ gamma.slopek);
break;
}
case MXCFB_WAIT_FOR_VSYNC:
@@ -876,7 +937,8 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
int i;
for (i = 0; i < num_registered_fb; i++) {
bg_mxcfbi =
- ((struct mxcfb_info *)(registered_fb[i]->par));
+ ((struct mxcfb_info
+ *)(registered_fb[i]->par));
if (bg_mxcfbi->ipu_ch == MEM_BG_SYNC)
break;
@@ -891,21 +953,25 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
}
- down(&mxc_fbi->flip_sem);
init_completion(&mxc_fbi->vsync_complete);
ipu_clear_irq(mxc_fbi->ipu_ch_irq);
+ mxc_fbi->wait4vsync = 1;
ipu_enable_irq(mxc_fbi->ipu_ch_irq);
- retval = wait_for_completion_interruptible_timeout(
- &mxc_fbi->vsync_complete, 1 * HZ);
+ retval =
+ wait_for_completion_interruptible_timeout(&mxc_fbi->
+ vsync_complete,
+ 1 * HZ);
if (retval == 0) {
dev_err(fbi->device,
"MXCFB_WAIT_FOR_VSYNC: timeout %d\n",
retval);
+ mxc_fbi->wait4vsync = 0;
retval = -ETIME;
} else if (retval > 0) {
retval = 0;
}
+
break;
}
case FBIO_ALLOC:
@@ -986,7 +1052,8 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
for (i = 0; i < num_registered_fb; i++) {
bg_mxcfbi =
- ((struct mxcfb_info *)(registered_fb[i]->par));
+ ((struct mxcfb_info *)(registered_fb[i]->
+ par));
if (bg_mxcfbi->ipu_ch == MEM_BG_SYNC) {
bg_fbi = registered_fb[i];
@@ -1005,13 +1072,15 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
if (bg_fbi->var.xres < fbi->var.xres)
pos.x = 0;
else
- pos.x = bg_fbi->var.xres - fbi->var.xres;
+ pos.x =
+ bg_fbi->var.xres - fbi->var.xres;
}
if (fbi->var.yres + pos.y > bg_fbi->var.yres) {
if (bg_fbi->var.yres < fbi->var.yres)
pos.y = 0;
else
- pos.y = bg_fbi->var.yres - fbi->var.yres;
+ pos.y =
+ bg_fbi->var.yres - fbi->var.yres;
}
retval = ipu_disp_set_window_pos(mxc_fbi->ipu_ch,
@@ -1026,12 +1095,39 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
case MXCFB_GET_FB_IPU_CHAN:
{
struct mxcfb_info *mxc_fbi =
- (struct mxcfb_info *)fbi->par;
+ (struct mxcfb_info *)fbi->par;
if (put_user(mxc_fbi->ipu_ch, argp))
return -EFAULT;
break;
}
+ case MXCFB_GET_DIFMT:
+ {
+ struct mxcfb_info *mxc_fbi =
+ (struct mxcfb_info *)fbi->par;
+
+ if (put_user(mxc_fbi->ipu_di_pix_fmt, argp))
+ return -EFAULT;
+ break;
+ }
+ case MXCFB_GET_FB_IPU_DI:
+ {
+ struct mxcfb_info *mxc_fbi =
+ (struct mxcfb_info *)fbi->par;
+
+ if (put_user(mxc_fbi->ipu_di, argp))
+ return -EFAULT;
+ break;
+ }
+ case MXCFB_GET_FB_BLANK:
+ {
+ struct mxcfb_info *mxc_fbi =
+ (struct mxcfb_info *)fbi->par;
+
+ if (put_user(mxc_fbi->cur_blank, argp))
+ return -EFAULT;
+ break;
+ }
default:
retval = -EINVAL;
}
@@ -1081,7 +1177,7 @@ static int
mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par,
- *mxc_graphic_fbi = NULL;
+ *mxc_graphic_fbi = NULL;
u_int y_bottom;
unsigned long base, active_alpha_phy_addr = 0;
bool loc_alpha_en = false;
@@ -1102,7 +1198,7 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
int j;
for (j = 0; j < num_registered_fb; j++) {
bg_mxcfbi =
- ((struct mxcfb_info *)(registered_fb[j]->par));
+ ((struct mxcfb_info *)(registered_fb[j]->par));
if (bg_mxcfbi->ipu_ch == MEM_BG_SYNC)
break;
@@ -1122,12 +1218,9 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
return -EINVAL;
base = (var->yoffset * var->xres_virtual + var->xoffset);
- base *= (var->bits_per_pixel) / 8;
+ base = (var->bits_per_pixel) * base / 8;
base += info->fix.smem_start;
- dev_dbg(info->device, "Updating SDC %s buf %d address=0x%08lX\n",
- info->fix.id, mxc_fbi->cur_ipu_buf, base);
-
/* Check if DP local alpha is enabled and find the graphic fb */
if (mxc_fbi->ipu_ch == MEM_BG_SYNC || mxc_fbi->ipu_ch == MEM_FG_SYNC) {
for (i = 0; i < num_registered_fb; i++) {
@@ -1135,13 +1228,13 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
if ((strcmp(idstr, "DISP3 BG") == 0 ||
strcmp(idstr, "DISP3 FG") == 0) &&
((struct mxcfb_info *)
- (registered_fb[i]->par))->alpha_chan_en) {
+ (registered_fb[i]->par))->alpha_chan_en) {
loc_alpha_en = true;
mxc_graphic_fbi = (struct mxcfb_info *)
- (registered_fb[i]->par);
+ (registered_fb[i]->par);
active_alpha_phy_addr = mxc_fbi->cur_ipu_buf ?
- mxc_graphic_fbi->alpha_phy_addr1 :
- mxc_graphic_fbi->alpha_phy_addr0;
+ mxc_graphic_fbi->alpha_phy_addr1 :
+ mxc_graphic_fbi->alpha_phy_addr0;
dev_dbg(info->device, "Updating SDC graphic "
"buf %d address=0x%08lX\n",
mxc_fbi->cur_ipu_buf,
@@ -1151,10 +1244,13 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
}
}
- down(&mxc_fbi->flip_sem);
init_completion(&mxc_fbi->vsync_complete);
mxc_fbi->cur_ipu_buf = !mxc_fbi->cur_ipu_buf;
+
+ dev_dbg(info->device, "Updating SDC %s buf %d address=0x%08lX\n",
+ info->fix.id, mxc_fbi->cur_ipu_buf, base);
+
if (ipu_update_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
mxc_fbi->cur_ipu_buf, base) == 0) {
/* Update the DP local alpha buffer only for graphic plane */
@@ -1176,8 +1272,13 @@ mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
dev_err(info->device,
"Error updating SDC buf %d to address=0x%08lX\n",
mxc_fbi->cur_ipu_buf, base);
+ mxc_fbi->cur_ipu_buf = !mxc_fbi->cur_ipu_buf;
+ ipu_clear_irq(mxc_fbi->ipu_ch_irq);
+ ipu_enable_irq(mxc_fbi->ipu_ch_irq);
+ return -EBUSY;
}
+ down(&mxc_fbi->flip_sem);
dev_dbg(info->device, "Update complete\n");
info->var.xoffset = var->xoffset;
@@ -1211,9 +1312,9 @@ static int mxcfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
len = fbi->fix.smem_len - offset;
vma->vm_pgoff = (fbi->fix.smem_start + offset) >> PAGE_SHIFT;
} else if ((vma->vm_pgoff ==
- (mxc_fbi->alpha_phy_addr0 >> PAGE_SHIFT)) ||
+ (mxc_fbi->alpha_phy_addr0 >> PAGE_SHIFT)) ||
(vma->vm_pgoff ==
- (mxc_fbi->alpha_phy_addr1 >> PAGE_SHIFT))) {
+ (mxc_fbi->alpha_phy_addr1 >> PAGE_SHIFT))) {
len = mxc_fbi->alpha_mem_len;
} else {
list_for_each_entry(mem, &fb_alloc_list, list) {
@@ -1269,9 +1370,14 @@ static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id)
struct fb_info *fbi = dev_id;
struct mxcfb_info *mxc_fbi = fbi->par;
- complete(&mxc_fbi->vsync_complete);
- up(&mxc_fbi->flip_sem);
- ipu_disable_irq(irq);
+ if (mxc_fbi->wait4vsync) {
+ complete(&mxc_fbi->vsync_complete);
+ ipu_disable_irq(irq);
+ mxc_fbi->wait4vsync = 0;
+ } else {
+ up(&mxc_fbi->flip_sem);
+ ipu_disable_irq(irq);
+ }
return IRQ_HANDLED;
}
@@ -1288,14 +1394,10 @@ static irqreturn_t mxcfb_alpha_irq_handler(int irq, void *dev_id)
/*
* Suspends the framebuffer and blanks the screen. Power management support
*/
-static int mxcfb_suspend(struct platform_device *pdev, pm_message_t state)
+static void mxcfb_suspend_one(struct fb_info *fbi)
{
- struct fb_info *fbi = platform_get_drvdata(pdev);
struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
int saved_blank;
-#ifdef CONFIG_FB_MXC_LOW_PWR_DISPLAY
- void *fbmem;
-#endif
acquire_console_sem();
fb_set_suspend(fbi, 1);
@@ -1303,25 +1405,43 @@ static int mxcfb_suspend(struct platform_device *pdev, pm_message_t state)
mxcfb_blank(FB_BLANK_POWERDOWN, fbi);
mxc_fbi->next_blank = saved_blank;
release_console_sem();
-
- return 0;
}
/*
* Resumes the framebuffer and unblanks the screen. Power management support
*/
-static int mxcfb_resume(struct platform_device *pdev)
+static void mxcfb_resume_one(struct fb_info *fbi)
{
- struct fb_info *fbi = platform_get_drvdata(pdev);
struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
acquire_console_sem();
mxcfb_blank(mxc_fbi->next_blank, fbi);
fb_set_suspend(fbi, 0);
release_console_sem();
+}
+
+#ifndef CONFIG_HAS_EARLYSUSPEND
+
+static int mxcfb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct fb_info *fbi = platform_get_drvdata(pdev);
+
+ if (fbi && (strcmp(fbi->fix.id, "DISP3 FG") == 0))
+ mxcfb_suspend_one(fbi);
+
+ return 0;
+}
+
+static int mxcfb_resume(struct platform_device *pdev)
+{
+ struct fb_info *fbi = platform_get_drvdata(pdev);
+
+ if (fbi && (strcmp(fbi->fix.id, "DISP3 FG") == 0))
+ mxcfb_resume_one(fbi);
return 0;
}
+#endif
/*
* Main framebuffer functions
@@ -1341,12 +1461,12 @@ static int mxcfb_map_video_memory(struct fb_info *fbi)
{
if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length)
fbi->fix.smem_len = fbi->var.yres_virtual *
- fbi->fix.line_length;
+ fbi->fix.line_length;
fbi->screen_base = dma_alloc_writecombine(fbi->device,
- fbi->fix.smem_len,
- (dma_addr_t *)&fbi->fix.smem_start,
- GFP_DMA);
+ fbi->fix.smem_len,
+ (dma_addr_t *) & fbi->fix.
+ smem_start, GFP_DMA);
if (fbi->screen_base == 0) {
dev_err(fbi->device, "Unable to allocate framebuffer memory\n");
fbi->fix.smem_len = 0;
@@ -1443,6 +1563,7 @@ static ssize_t swap_disp_chan(struct device *dev,
struct mxcfb_info *mxcfbi = (struct mxcfb_info *)info->par;
struct mxcfb_info *fg_mxcfbi = NULL;
+ acquire_console_sem();
/* swap only happen between DP-BG and DC, while DP-FG disable */
if (((mxcfbi->ipu_ch == MEM_BG_SYNC) &&
(strstr(buf, "1-layer-fb") != NULL)) ||
@@ -1451,17 +1572,16 @@ static ssize_t swap_disp_chan(struct device *dev,
int i;
for (i = 0; i < num_registered_fb; i++) {
- fg_mxcfbi =
- (struct mxcfb_info *)mxcfb_info[i]->par;
+ fg_mxcfbi = (struct mxcfb_info *)mxcfb_info[i]->par;
if (fg_mxcfbi->ipu_ch == MEM_FG_SYNC)
break;
else
fg_mxcfbi = NULL;
}
- if (!fg_mxcfbi ||
- fg_mxcfbi->cur_blank == FB_BLANK_UNBLANK) {
+ if (!fg_mxcfbi || fg_mxcfbi->cur_blank == FB_BLANK_UNBLANK) {
dev_err(dev,
"Can not switch while fb2(fb-fg) is on.\n");
+ release_console_sem();
return count;
}
@@ -1469,8 +1589,10 @@ static ssize_t swap_disp_chan(struct device *dev,
dev_err(dev, "Swap display channel failed.\n");
}
+ release_console_sem();
return count;
}
+
DEVICE_ATTR(fsl_disp_property, 644, show_disp_chan, swap_disp_chan);
/*!
@@ -1487,6 +1609,8 @@ static int mxcfb_probe(struct platform_device *pdev)
struct mxcfb_info *mxcfbi;
struct mxc_fb_platform_data *plat_data = pdev->dev.platform_data;
struct resource *res;
+ char *options, *mstr;
+ char name[] = "mxcdi0fb";
int ret = 0;
/*
@@ -1499,6 +1623,13 @@ static int mxcfb_probe(struct platform_device *pdev)
}
mxcfbi = (struct mxcfb_info *)fbi->par;
+ name[5] += pdev->id;
+ if (fb_get_options(name, &options))
+ return -ENODEV;
+
+ if (options)
+ mxcfb_option_setup(fbi, options);
+
if (!g_dp_in_use) {
mxcfbi->ipu_ch_irq = IPU_IRQ_BG_SYNC_EOF;
mxcfbi->ipu_ch = MEM_BG_SYNC;
@@ -1521,7 +1652,7 @@ static int mxcfb_probe(struct platform_device *pdev)
mxcfb_alpha_irq_handler, 0,
MXCFB_NAME, fbi) != 0) {
dev_err(&pdev->dev, "Error registering BG "
- "alpha irq handler.\n");
+ "alpha irq handler.\n");
ret = -EBUSY;
goto err1;
}
@@ -1534,7 +1665,7 @@ static int mxcfb_probe(struct platform_device *pdev)
mxcfb_alpha_irq_handler, 0,
MXCFB_NAME, fbi) != 0) {
dev_err(&pdev->dev, "Error registering BG "
- "alpha irq handler.\n");
+ "alpha irq handler.\n");
ret = -EBUSY;
goto err1;
}
@@ -1552,7 +1683,7 @@ static int mxcfb_probe(struct platform_device *pdev)
mxcfb_alpha_irq_handler, 0,
MXCFB_NAME, fbi) != 0) {
dev_err(&pdev->dev, "Error registering FG alpha irq "
- "handler.\n");
+ "handler.\n");
ret = -EBUSY;
goto err1;
}
@@ -1572,31 +1703,63 @@ static int mxcfb_probe(struct platform_device *pdev)
if (res && res->end) {
fbi->fix.smem_len = res->end - res->start + 1;
fbi->fix.smem_start = res->start;
- fbi->screen_base = ioremap(fbi->fix.smem_start, fbi->fix.smem_len);
+ fbi->screen_base =
+ ioremap(fbi->fix.smem_start, fbi->fix.smem_len);
}
/* Need dummy values until real panel is configured */
fbi->var.xres = 240;
fbi->var.yres = 320;
- if (!fb_mode && plat_data && plat_data->mode_str)
- fb_find_mode(&fbi->var, fbi, plat_data->mode_str, NULL, 0, NULL,
- default_bpp);
-
- if (fb_mode)
- fb_find_mode(&fbi->var, fbi, fb_mode, NULL, 0, NULL,
- default_bpp);
+ if (!mxcfbi->default_bpp)
+#ifdef CONFIG_CCWMX51_DEFAULT_VIDEO_BPP
+ mxcfbi->default_bpp = CONFIG_CCWMX51_DEFAULT_VIDEO_BPP;
+#else
+ mxcfbi->default_bpp = 16;
+#endif
- if (plat_data) {
+ if (plat_data && !mxcfbi->ipu_di_pix_fmt)
mxcfbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt;
- if (!fb_mode && plat_data->mode)
- fb_videomode_to_var(&fbi->var, plat_data->mode);
+
+ if (plat_data && plat_data->mode && plat_data->num_modes)
+ fb_videomode_to_modelist(plat_data->mode, plat_data->num_modes,
+ &fbi->modelist);
+
+ if (!mxcfbi->fb_mode_str && plat_data && plat_data->mode_str)
+ mxcfbi->fb_mode_str = plat_data->mode_str;
+
+ if (mxcfbi->fb_mode_str) {
+
+#ifdef CONFIG_MODULE_CCXMX51
+ if ((mstr = strstr(mxcfbi->fb_mode_str, "VGA@")) != NULL)
+ mxcfbi->fb_mode_str = mstr + 4;
+#endif
+
+ ret =
+ fb_find_mode(&fbi->var, fbi, mxcfbi->fb_mode_str, NULL, 0,
+ NULL, mxcfbi->default_bpp);
+ if ((!ret || (ret > 2)) && plat_data && plat_data->mode
+ && plat_data->num_modes)
+ fb_find_mode(&fbi->var, fbi, mxcfbi->fb_mode_str,
+ plat_data->mode, plat_data->num_modes,
+ NULL, mxcfbi->default_bpp);
+
+#ifdef CONFIG_MODULE_CCXMX51
+ /* This improves the VGA modes on the CCWi-i.MX51 */
+ if (mstr != NULL) {
+ mxcfbi->ipu_ext_clk = true;
+ fbi->var.sync |= FB_SYNC_CLK_LAT_FALL;
+ }
+#endif
}
mxcfb_check_var(&fbi->var, fbi);
+ pm_set_vt_switch(vt_switch);
+
/* Default Y virtual size is 2x panel size */
- fbi->var.yres_virtual = fbi->var.yres * 3;
+ fbi->var.yres_virtual = ((fbi->var.yres + 127) & ~127) * 2;
+ fbi->var.xres_virtual = (fbi->var.xres + 31) & ~31;
mxcfb_set_fix(fbi);
@@ -1617,12 +1780,12 @@ static int mxcfb_probe(struct platform_device *pdev)
return 0;
-err2:
+ err2:
ipu_free_irq(mxcfbi->ipu_ch_irq, fbi);
-err1:
+ err1:
fb_dealloc_cmap(&fbi->cmap);
framebuffer_release(fbi);
-err0:
+ err0:
return ret;
}
@@ -1655,38 +1818,108 @@ static struct platform_driver mxcfb_driver = {
},
.probe = mxcfb_probe,
.remove = mxcfb_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = mxcfb_suspend,
.resume = mxcfb_resume,
+#endif
};
/*
* Parse user specified options (`video=trident:')
* example:
- * video=trident:800x600,bpp=16,noaccel
+ * video=mxcdi0fb:RGB24, 1024x768M-16@60,bpp=16,noaccel
*/
-int mxcfb_setup(char *options)
+static int mxcfb_option_setup(struct fb_info *info, char *options)
{
+ struct mxcfb_info *mxcfbi = info->par;
char *opt;
+
if (!options || !*options)
return 0;
+
while ((opt = strsep(&options, ",")) != NULL) {
if (!*opt)
continue;
+
+ if (!strncmp(opt, "RGB24", 5)) {
+ mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_RGB24;
+ continue;
+ }
+ if (!strncmp(opt, "BGR24", 5)) {
+ mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_BGR24;
+ continue;
+ }
+ if (!strncmp(opt, "RGB565", 6)) {
+ mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_RGB565;
+ continue;
+ }
+ if (!strncmp(opt, "RGB666", 6)) {
+ mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_RGB666;
+ continue;
+ }
+ if (!strncmp(opt, "YUV444", 6)) {
+ mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_YUV444;
+ continue;
+ }
+ if (!strncmp(opt, "LVDS666", 7)) {
+ mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_LVDS666;
+ continue;
+ }
+ if (!strncmp(opt, "YUYV16", 6)) {
+ mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_YUYV;
+ continue;
+ }
+ if (!strncmp(opt, "UYVY16", 6)) {
+ mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_UYVY;
+ continue;
+ }
+ if (!strncmp(opt, "YVYU16", 6)) {
+ mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_YVYU;
+ continue;
+ }
+ if (!strncmp(opt, "VYUY16", 6)) {
+ mxcfbi->ipu_di_pix_fmt = IPU_PIX_FMT_VYUY;
+ continue;
+ }
if (!strncmp(opt, "ext_clk", 7)) {
- ext_clk_used = true;
+ mxcfbi->ipu_ext_clk = true;
continue;
- } else
- ext_clk_used = false;
-
+ }
if (!strncmp(opt, "bpp=", 4))
- default_bpp = simple_strtoul(opt + 4, NULL, 0);
+ mxcfbi->default_bpp = simple_strtoul(opt + 4, NULL, 0);
else
- fb_mode = opt;
-
+ mxcfbi->fb_mode_str = opt;
}
+
return 0;
}
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void mxcfb_early_suspend(struct early_suspend *h)
+{
+ int i;
+ for (i = FB_DEVICE_NUM - 1; i >= 0; i--) {
+ if (mxcfb_info[i])
+ mxcfb_suspend_one(mxcfb_info[i]);
+ }
+}
+
+static void mxcfb_later_resume(struct early_suspend *h)
+{
+ int i;
+ for (i = 0; i < FB_DEVICE_NUM; i++) {
+ if (mxcfb_info[i])
+ mxcfb_resume_one(mxcfb_info[i]);
+ }
+}
+
+struct early_suspend fbdrv_earlysuspend = {
+ .level = EARLY_SUSPEND_LEVEL_DISABLE_FB,
+ .suspend = mxcfb_early_suspend,
+ .resume = mxcfb_later_resume,
+};
+#endif
+
/*!
* Main entry function for the framebuffer. The function registers the power
* management callback functions with the kernel and also registers the MXCFB
@@ -1696,26 +1929,23 @@ int mxcfb_setup(char *options)
*/
int __init mxcfb_init(void)
{
- int ret = 0;
-#ifndef MODULE
- char *option = NULL;
-#endif
-
-#ifndef MODULE
- if (fb_get_options("mxcfb", &option))
- return -ENODEV;
- mxcfb_setup(option);
-#endif
+ int ret;
ret = platform_driver_register(&mxcfb_driver);
+ if (!ret)
+ register_early_suspend(&fbdrv_earlysuspend);
return ret;
}
void mxcfb_exit(void)
{
+ unregister_early_suspend(&fbdrv_earlysuspend);
platform_driver_unregister(&mxcfb_driver);
}
+module_param(vt_switch, int, 0);
+MODULE_PARM_DESC(vt_switch, "enable VT switch during suspend/resume");
+
module_init(mxcfb_init);
module_exit(mxcfb_exit);
diff --git a/drivers/video/mxc/mxcfb_claa_wvga.c b/drivers/video/mxc/mxcfb_claa_wvga.c
index bd5ff7b83f8c..8f696c19e7d9 100644
--- a/drivers/video/mxc/mxcfb_claa_wvga.c
+++ b/drivers/video/mxc/mxcfb_claa_wvga.c
@@ -48,8 +48,8 @@ static int lcd_on;
static struct fb_videomode video_modes[] = {
{
- /* 800x480 @ 55 Hz , pixel clk @ 25MHz */
- "CLAA-WVGA", 55, 800, 480, 40000, 40, 40, 5, 5, 20, 10,
+ /* 800x480 @ 57 Hz , pixel clk @ 27MHz */
+ "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10,
FB_SYNC_CLK_LAT_FALL,
FB_VMODE_NONINTERLACED,
0,},
@@ -77,13 +77,14 @@ static int lcd_fb_event(struct notifier_block *nb, unsigned long val, void *v)
{
struct fb_event *event = v;
- if (strcmp(event->info->fix.id, "DISP3 BG")) {
+ if (strcmp(event->info->fix.id, "DISP3 BG") &&
+ strcmp(event->info->fix.id, "mxc_elcdif_fb"))
return 0;
- }
switch (val) {
case FB_EVENT_FB_REGISTERED:
lcd_init_fb(event->info);
+ fb_show_logo(event->info, 0);
lcd_poweron();
break;
case FB_EVENT_BLANK:
@@ -133,7 +134,8 @@ static int __devinit lcd_probe(struct platform_device *pdev)
}
for (i = 0; i < num_registered_fb; i++) {
- if (strcmp(registered_fb[i]->fix.id, "DISP3 BG") == 0) {
+ if (strcmp(registered_fb[i]->fix.id, "DISP3 BG") == 0 ||
+ strcmp(registered_fb[i]->fix.id, "mxc_elcdif_fb") == 0) {
lcd_init_fb(registered_fb[i]);
fb_show_logo(registered_fb[i], 0);
lcd_poweron();
diff --git a/drivers/video/mxc/tve.c b/drivers/video/mxc/tve.c
index 2d2929c0cbd9..793b470cdce4 100644
--- a/drivers/video/mxc/tve.c
+++ b/drivers/video/mxc/tve.c
@@ -68,6 +68,8 @@ static int enabled; /* enable power on or not */
DEFINE_SPINLOCK(tve_lock);
static struct fb_info *tve_fbi;
+static struct fb_modelist tve_modelist;
+static bool g_enable_tve;
struct tve_data {
struct platform_device *pdev;
@@ -77,6 +79,7 @@ struct tve_data {
int detect;
void *base;
int irq;
+ int blank;
struct clk *clk;
struct regulator *dac_reg;
struct regulator *dig_reg;
@@ -221,40 +224,50 @@ static int _is_tvout_mode_hd_compatible(void)
static int tve_setup(int mode)
{
u32 reg;
- struct clk *pll3_clk;
- unsigned long pll3_clock_rate = 216000000, di1_clock_rate = 27000000;
+ struct clk *tve_parent_clk;
+ unsigned long parent_clock_rate = 216000000, di1_clock_rate = 27000000;
+ unsigned long tve_clock_rate = 216000000;
struct clk *ipu_di1_clk;
unsigned long lock_flags;
- if (tve.cur_mode == mode)
- return 0;
-
spin_lock_irqsave(&tve_lock, lock_flags);
- tve.cur_mode = mode;
-
switch (mode) {
case TVOUT_FMT_PAL:
case TVOUT_FMT_NTSC:
- pll3_clock_rate = 216000000;
+ parent_clock_rate = 216000000;
di1_clock_rate = 27000000;
break;
case TVOUT_FMT_720P60:
- pll3_clock_rate = 297000000;
+ parent_clock_rate = 297000000;
+ if (cpu_is_mx53())
+ tve_clock_rate = 297000000;
di1_clock_rate = 74250000;
break;
}
if (enabled)
clk_disable(tve.clk);
- pll3_clk = clk_get(NULL, "pll3");
+ tve_parent_clk = clk_get_parent(tve.clk);
ipu_di1_clk = clk_get(NULL, "ipu_di1_clk");
- clk_disable(pll3_clk);
- clk_set_rate(pll3_clk, pll3_clock_rate);
- clk_set_rate(ipu_di1_clk, di1_clock_rate);
+ clk_disable(tve_parent_clk);
+ clk_set_rate(tve_parent_clk, parent_clock_rate);
+
+ if (cpu_is_mx53())
+ clk_set_rate(tve.clk, tve_clock_rate);
clk_enable(tve.clk);
+ clk_set_rate(ipu_di1_clk, di1_clock_rate);
+
+ if (tve.cur_mode == mode) {
+ if (!enabled)
+ clk_disable(tve.clk);
+ spin_unlock_irqrestore(&tve_lock, lock_flags);
+ return 0;
+ }
+
+ tve.cur_mode = mode;
/* select output video format */
if (mode == TVOUT_FMT_PAL) {
@@ -497,6 +510,14 @@ static irqreturn_t tve_detect_handler(int irq, void *data)
return IRQ_HANDLED;
}
+/* Re-construct clk for tve display */
+static inline void tve_recfg_fb(struct fb_info *fbi)
+{
+ fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ fbi->var.activate |= FB_ACTIVATE_FORCE;
+ fb_set_var(fbi, &fbi->var);
+}
+
int tve_fb_event(struct notifier_block *nb, unsigned long val, void *v)
{
struct fb_event *event = v;
@@ -509,9 +530,9 @@ int tve_fb_event(struct notifier_block *nb, unsigned long val, void *v)
break;
tve_fbi = fbi;
- fb_add_videomode(&video_modes[0], &tve_fbi->modelist);
- fb_add_videomode(&video_modes[1], &tve_fbi->modelist);
- fb_add_videomode(&video_modes[2], &tve_fbi->modelist);
+ fb_add_videomode(&video_modes[0], &tve_modelist.list);
+ fb_add_videomode(&video_modes[1], &tve_modelist.list);
+ fb_add_videomode(&video_modes[2], &tve_modelist.list);
break;
case FB_EVENT_MODE_CHANGE:
{
@@ -525,7 +546,7 @@ int tve_fb_event(struct notifier_block *nb, unsigned long val, void *v)
fb_var_to_videomode(&cur_mode, &fbi->var);
- list_for_each(pos, &tve_fbi->modelist) {
+ list_for_each(pos, &tve_modelist.list) {
modelist = list_entry(pos, struct fb_modelist, list);
mode = &modelist->mode;
if (fb_mode_is_equal(&cur_mode, mode)) {
@@ -564,31 +585,33 @@ int tve_fb_event(struct notifier_block *nb, unsigned long val, void *v)
return 0;
if (*((int *)event->data) == FB_BLANK_UNBLANK) {
- if (fb_mode_is_equal(fbi->mode, &video_modes[0])) {
- if (tve.cur_mode != TVOUT_FMT_NTSC) {
+ if (tve.blank != FB_BLANK_UNBLANK) {
+ if (fb_mode_is_equal(fbi->mode, &video_modes[0])) {
tve_disable();
tve_setup(TVOUT_FMT_NTSC);
- }
- tve_enable();
- } else if (fb_mode_is_equal(fbi->mode,
- &video_modes[1])) {
- if (tve.cur_mode != TVOUT_FMT_PAL) {
+ tve_enable();
+ tve_recfg_fb(fbi);
+ } else if (fb_mode_is_equal(fbi->mode,
+ &video_modes[1])) {
tve_disable();
tve_setup(TVOUT_FMT_PAL);
- }
- tve_enable();
- } else if (fb_mode_is_equal(fbi->mode,
- &video_modes[2])) {
- if (tve.cur_mode != TVOUT_FMT_720P60) {
+ tve_enable();
+ tve_recfg_fb(fbi);
+ } else if (fb_mode_is_equal(fbi->mode,
+ &video_modes[2])) {
tve_disable();
tve_setup(TVOUT_FMT_720P60);
+ tve_enable();
+ tve_recfg_fb(fbi);
+ } else {
+ tve_setup(TVOUT_FMT_OFF);
}
- tve_enable();
- } else {
- tve_setup(TVOUT_FMT_OFF);
+ tve.blank = FB_BLANK_UNBLANK;
}
- } else
+ } else {
tve_disable();
+ tve.blank = FB_BLANK_POWERDOWN;
+ }
break;
}
return 0;
@@ -652,6 +675,11 @@ static int tve_probe(struct platform_device *pdev)
struct tve_platform_data *plat_data = pdev->dev.platform_data;
u32 conf_reg;
+ if (g_enable_tve == false)
+ return -ENODEV;
+
+ INIT_LIST_HEAD(&tve_modelist.list);
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL)
return -ENOMEM;
@@ -699,9 +727,9 @@ static int tve_probe(struct platform_device *pdev)
}
if (tve_fbi != NULL) {
- fb_add_videomode(&video_modes[0], &tve_fbi->modelist);
- fb_add_videomode(&video_modes[1], &tve_fbi->modelist);
- fb_add_videomode(&video_modes[2], &tve_fbi->modelist);
+ fb_add_videomode(&video_modes[0], &tve_modelist.list);
+ fb_add_videomode(&video_modes[1], &tve_modelist.list);
+ fb_add_videomode(&video_modes[2], &tve_modelist.list);
}
tve.dac_reg = regulator_get(&pdev->dev, plat_data->dac_reg);
@@ -748,22 +776,40 @@ static int tve_probe(struct platform_device *pdev)
clk_disable(tve.clk);
+ ret = fb_register_client(&nb);
+ if (ret < 0)
+ goto err2;
+
+ tve.blank = -1;
+
/* is primary display? */
if (primary) {
- struct fb_event event;
+ struct fb_var_screeninfo var;
+ const struct fb_videomode *mode;
+
+ memset(&var, 0, sizeof(var));
+ mode = fb_match_mode(&tve_fbi->var, &tve_modelist.list);
+ if (mode) {
+ pr_debug("TVE: fb mode found\n");
+ fb_videomode_to_var(&var, mode);
+ } else {
+ pr_warning("TVE: can not find video mode\n");
+ goto done;
+ }
+ acquire_console_sem();
+ tve_fbi->flags |= FBINFO_MISC_USEREVENT;
+ fb_set_var(tve_fbi, &var);
+ tve_fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ release_console_sem();
- event.info = tve_fbi;
- tve_fb_event(NULL, FB_EVENT_MODE_CHANGE, &event);
acquire_console_sem();
fb_blank(tve_fbi, FB_BLANK_UNBLANK);
release_console_sem();
+
fb_show_logo(tve_fbi, 0);
}
- ret = fb_register_client(&nb);
- if (ret < 0)
- goto err2;
-
+done:
return 0;
err2:
device_remove_file(&pdev->dev, &dev_attr_headphone);
@@ -842,6 +888,14 @@ static struct platform_driver tve_driver = {
.resume = tve_resume,
};
+static int __init enable_tve_setup(char *options)
+{
+ g_enable_tve = true;
+
+ return 1;
+}
+__setup("tve", enable_tve_setup);
+
static int __init tve_init(void)
{
return platform_driver_register(&tve_driver);
diff --git a/drivers/video/mxs/Kconfig b/drivers/video/mxs/Kconfig
index aef4aa59dcad..35b896e95d4f 100644
--- a/drivers/video/mxs/Kconfig
+++ b/drivers/video/mxs/Kconfig
@@ -20,3 +20,9 @@ config FB_MXS_LCD_LMS430
default y if ARCH_MX23
---help---
Use LMS430 dotclock LCD panel for MXS
+
+config FB_MXS_TVENC
+ depends on ARCH_MXS
+ bool "TVENC"
+ ---help---
+ Use TVOUT encoder for MXS
diff --git a/drivers/video/mxs/Makefile b/drivers/video/mxs/Makefile
index a9580add3757..fbab953718c7 100644
--- a/drivers/video/mxs/Makefile
+++ b/drivers/video/mxs/Makefile
@@ -2,3 +2,5 @@ obj-$(CONFIG_ARCH_MXS) += lcdif.o
obj-$(CONFIG_FB_MXS) += mxsfb.o
obj-$(CONFIG_FB_MXS_LCD_43WVF1G) += lcd_43wvf1g.o
obj-$(CONFIG_FB_MXS_LCD_LMS430) += lcd_lms430.o
+# TVOUT support
+obj-$(CONFIG_FB_MXS_TVENC) += tvenc.o
diff --git a/drivers/watchdog/mxc_wdt.c b/drivers/watchdog/mxc_wdt.c
index 3626a51e557d..0114fab70253 100644
--- a/drivers/watchdog/mxc_wdt.c
+++ b/drivers/watchdog/mxc_wdt.c
@@ -200,7 +200,7 @@ mxc_wdt_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user((struct watchdog_info __user *)arg, &ident,
sizeof(ident));
diff --git a/firmware/Makefile b/firmware/Makefile
index 621de8e952f7..19d80a6cc763 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -110,6 +110,8 @@ fw-shipped-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda/xircom_pgs.fw
fw-shipped-$(CONFIG_USB_VICAM) += vicam/firmware.fw
fw-shipped-$(CONFIG_VIDEO_CPIA2) += cpia2/stv0672_vp4.bin
fw-shipped-$(CONFIG_YAM) += yam/1200.bin yam/9600.bin
+fw-shipped-$(CONFIG_FB_MXC_EINK_PANEL) += imx/epdc_E60.fw \
+ imx/epdc_E97.fw
fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-)
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 530b4ca01510..4ceff5110417 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -758,6 +758,13 @@ static int fat_ioctl_readdir(struct inode *inode, struct file *filp,
return ret;
}
+static int fat_ioctl_volume_id(struct inode *dir)
+{
+ struct super_block *sb = dir->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ return sbi->vol_id;
+}
+
static int fat_dir_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
@@ -773,6 +780,8 @@ static int fat_dir_ioctl(struct inode *inode, struct file *filp,
short_only = 0;
both = 1;
break;
+ case VFAT_IOCTL_GET_VOLUME_ID:
+ return fat_ioctl_volume_id(inode);
default:
return fat_generic_ioctl(inode, filp, cmd, arg);
}
diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index adb0e72a176d..09305185330f 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -76,6 +76,7 @@ struct msdos_sb_info {
const void *dir_ops; /* Opaque; default directory operations */
int dir_per_block; /* dir entries per block */
int dir_per_block_bits; /* log2(dir_per_block) */
+ unsigned long vol_id; /* volume ID */
int fatent_shift;
struct fatent_operations *fatent_ops;
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index ea4e6cb29e13..5ff78a202e0a 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -317,10 +317,19 @@ static void part_release(struct device *dev)
kfree(p);
}
+static int part_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct hd_struct *part = dev_to_part(dev);
+
+ add_uevent_var(env, "PARTN=%u", part->partno);
+ return 0;
+}
+
struct device_type part_type = {
.name = "partition",
.groups = part_attr_groups,
.release = part_release,
+ .uevent = part_uevent,
};
static void delete_partition_rcu_cb(struct rcu_head *head)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 6f742f6658a9..a0f94952faf2 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -127,6 +127,8 @@ struct pid_entry {
NOD(NAME, (S_IFREG|(MODE)), \
NULL, &proc_single_file_operations, \
{ .proc_show = show } )
+#define ARD(NAME, MODE, iops, fops) \
+ NOD(NAME, (S_IFREG|(MODE)), &iops, &fops, {} )
/*
* Count the number of hardlinks for the pid_entry table, excluding the .
@@ -1043,6 +1045,35 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
return end - buffer;
}
+#ifdef CONFIG_ANDROID
+static int oom_adjust_permission(struct inode *inode, int mask)
+{
+ uid_t uid;
+ struct task_struct *p = get_proc_task(inode);
+ if(p) {
+ uid = task_uid(p);
+ put_task_struct(p);
+ }
+
+ /*
+ * System Server (uid == 1000) is granted access to oom_adj of all
+ * android applications (uid > 10000) as and services (uid >= 1000)
+ */
+ if (p && (current_fsuid() == 1000) && (uid >= 1000)) {
+ if (inode->i_mode >> 6 & mask) {
+ return 0;
+ }
+ }
+
+ /* Fall back to default. */
+ return generic_permission(inode, mask, NULL);
+}
+
+static const struct inode_operations proc_oom_adjust_inode_operations = {
+ .permission = oom_adjust_permission,
+};
+#endif
+
static const struct file_operations proc_oom_adjust_operations = {
.read = oom_adjust_read,
.write = oom_adjust_write,
@@ -2531,7 +2562,11 @@ static const struct pid_entry tgid_base_stuff[] = {
REG("cgroup", S_IRUGO, proc_cgroup_operations),
#endif
INF("oom_score", S_IRUGO, proc_oom_score),
+#ifndef CONFIG_ANDROID
REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_operations),
+#else
+ ARD("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adjust_inode_operations, proc_oom_adjust_operations),
+#endif
#ifdef CONFIG_AUDITSYSCALL
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
REG("sessionid", S_IRUGO, proc_sessionid_operations),
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 9bd8be1d235c..07376a4a3ed1 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -689,8 +689,6 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
down_read(&current->mm->mmap_sem);
ret = get_user_pages(current, current->mm, uaddr, pagecount,
1, 0, pages, NULL);
- up_read(&current->mm->mmap_sem);
-
if (ret < 0)
goto out_free;
@@ -739,6 +737,7 @@ out_pages:
page_cache_release(page);
}
out_free:
+ up_read(&current->mm->mmap_sem);
kfree(pages);
out_mm:
mmput(mm);
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index a062aa3e2525..a9ad1f14f927 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -385,6 +385,7 @@ unifdef-y += mxc_mlb.h
unifdef-y += mxc_pf.h
unifdef-y += mxc_scc2_driver.h
unifdef-y += mxc_scc_driver.h
+unifdef-y += mxc_srtc.h
unifdef-y += mxc_si4702.h
unifdef-y += mxc_sim_interface.h
unifdef-y += mxc_v4l2.h
@@ -396,6 +397,7 @@ unifdef-y += pmic_light.h
unifdef-y += pmic_rtc.h
unifdef-y += pmic_status.h
unifdef-y += soundcard.h
+unifdef-y += pxp_dma.h
objhdr-y += version.h
header-y += wimax.h
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 9c75921f0c16..f5494050df83 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -306,6 +306,7 @@ enum {
/* SETFEATURE Sector counts for SATA features */
SATA_AN = 0x05, /* Asynchronous Notification */
SATA_DIPM = 0x03, /* Device Initiated Power Management */
+ SATA_FPDMA_AA = 0x02, /* DMA Setup FIS Auto-Activate */
/* feature values for SET_MAX */
ATA_SET_MAX_ADDR = 0x00,
@@ -525,6 +526,9 @@ static inline int ata_is_data(u8 prot)
#define ata_id_has_atapi_AN(id) \
( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \
((id)[78] & (1 << 5)) )
+#define ata_id_has_fpdma_aa(id) \
+ ( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \
+ ((id)[78] & (1 << 2)) )
#define ata_id_iordy_disable(id) ((id)[ATA_ID_CAPABILITY] & (1 << 10))
#define ata_id_has_iordy(id) ((id)[ATA_ID_CAPABILITY] & (1 << 11))
#define ata_id_u32(id,n) \
diff --git a/include/linux/fec.h b/include/linux/fec.h
index 2ad61317d32b..39ba482298e1 100644
--- a/include/linux/fec.h
+++ b/include/linux/fec.h
@@ -13,13 +13,34 @@
#ifndef __LINUX_FEC_H__
#define __LINUX_FEC_H__
+#include <linux/etherdevice.h>
#include <linux/phy.h>
struct fec_platform_data {
phy_interface_t phy;
+ unsigned int phy_mask;
+ unsigned char mac[ETH_ALEN];
int (*init)(void);
int (*uninit)(void);
struct regulator *vddio_reg;
};
+struct switch_platform_data {
+ int id;
+ int hash_table;
+ unsigned int *switch_hw;
+ struct fec_platform_data *fec_enet;
+ void (*request_intrs)(struct net_device *dev,
+ irqreturn_t (*)(int, void *),
+ void *irq_privatedata);
+ void (*set_mii)(struct net_device *dev);
+ void (*get_mac)(struct net_device *dev);
+ void (*enable_phy_intr)(void);
+ void (*disable_phy_intr)(void);
+ void (*phy_ack_intr)(void);
+ void (*localhw_setup)(void);
+ void (*uncache)(unsigned long addr);
+ void (*platform_flush_cache)(void);
+};
+
#endif
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 30a7ca46fa35..8ee3006f4678 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -93,6 +93,8 @@ struct fsl_usb2_platform_data {
void (*platform_suspend)(struct fsl_usb2_platform_data *);
void (*platform_resume)(struct fsl_usb2_platform_data *);
void (*wake_up_enable)(struct fsl_usb2_platform_data *pdata, bool on);
+ void (*phy_lowpower_suspend)(bool);
+ void (*platform_driver_vbus)(bool on); /* platform special function for vbus shutdown/open */
unsigned big_endian_mmio : 1;
unsigned big_endian_desc : 1;
unsigned es : 1; /* need USBMODE:ES */
diff --git a/include/linux/ipu.h b/include/linux/ipu.h
index 5a03856b1ac3..54a889b57f73 100644
--- a/include/linux/ipu.h
+++ b/include/linux/ipu.h
@@ -121,6 +121,8 @@ typedef enum {
/*! @{ */
#define IPU_PIX_FMT_YUYV fourcc('Y', 'U', 'Y', 'V') /*!< 16 YUV 4:2:2 */
#define IPU_PIX_FMT_UYVY fourcc('U', 'Y', 'V', 'Y') /*!< 16 YUV 4:2:2 */
+#define IPU_PIX_FMT_YVYU fourcc('Y', 'V', 'Y', 'U') /*!< 16 YVYU 4:2:2 */
+#define IPU_PIX_FMT_VYUY fourcc('V', 'Y', 'U', 'Y') /*!< 16 VYYU 4:2:2 */
#define IPU_PIX_FMT_Y41P fourcc('Y', '4', '1', 'P') /*!< 12 YUV 4:1:1 */
#define IPU_PIX_FMT_YUV444 fourcc('Y', '4', '4', '4') /*!< 24 YUV 4:4:4 */
/* two planes -- one Y, one Cb + Cr interleaved */
@@ -321,7 +323,8 @@ typedef union {
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
- uint32_t out_resize_ratio;
+ uint32_t outh_resize_ratio;
+ uint32_t outv_resize_ratio;
} mem_prp_enc_mem;
struct {
uint32_t in_width;
@@ -364,7 +367,8 @@ typedef union {
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
- uint32_t out_resize_ratio;
+ uint32_t outh_resize_ratio;
+ uint32_t outv_resize_ratio;
bool graphics_combine_en;
bool global_alpha_en;
bool key_color_en;
@@ -388,7 +392,8 @@ typedef union {
uint32_t out_width;
uint32_t out_height;
uint32_t out_pixel_fmt;
- uint32_t out_resize_ratio;
+ uint32_t outh_resize_ratio;
+ uint32_t outv_resize_ratio;
bool graphics_combine_en;
bool global_alpha_en;
bool key_color_en;
@@ -420,6 +425,8 @@ typedef union {
struct {
uint32_t di;
bool interlaced;
+ uint32_t in_pixel_fmt;
+ uint32_t out_pixel_fmt;
} mem_dc_sync;
struct {
uint32_t temp;
@@ -604,6 +611,9 @@ enum ipu_irq_line {
IPU_IRQ_CSI1_OUT_EOF = 1,
IPU_IRQ_CSI2_OUT_EOF = 2,
IPU_IRQ_CSI3_OUT_EOF = 3,
+ IPU_IRQ_VDI_P_IN_EOF = 8,
+ IPU_IRQ_VDI_C_IN_EOF = 9,
+ IPU_IRQ_VDI_N_IN_EOF = 10,
IPU_IRQ_PP_IN_EOF = 11,
IPU_IRQ_PRP_IN_EOF = 12,
IPU_IRQ_PRP_GRAPH_IN_EOF = 14,
@@ -895,6 +905,8 @@ int32_t ipu_link_channels(ipu_channel_t src_ch, ipu_channel_t dest_ch);
int32_t ipu_unlink_channels(ipu_channel_t src_ch, ipu_channel_t dest_ch);
int32_t ipu_is_channel_busy(ipu_channel_t channel);
+int32_t ipu_check_buffer_busy(ipu_channel_t channel, ipu_buffer_t type,
+ uint32_t bufNum);
void ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type,
uint32_t bufNum);
uint32_t ipu_get_cur_buffer_idx(ipu_channel_t channel, ipu_buffer_t type);
@@ -944,6 +956,8 @@ int32_t ipu_init_sync_panel(int disp,
int32_t ipu_disp_set_window_pos(ipu_channel_t channel, int16_t x_pos,
int16_t y_pos);
+int32_t ipu_disp_get_window_pos(ipu_channel_t channel, int16_t *x_pos,
+ int16_t *y_pos);
int32_t ipu_disp_set_global_alpha(ipu_channel_t channel, bool enable,
uint8_t alpha);
int32_t ipu_disp_set_color_key(ipu_channel_t channel, bool enable,
@@ -1260,6 +1274,7 @@ typedef struct _ipu_csc_update {
#define IPU_CALC_STRIPES_SIZE _IOWR('I', 0x27, ipu_stripe_parm)
#define IPU_UPDATE_BUF_OFFSET _IOW('I', 0x28, ipu_buf_offset_parm)
#define IPU_CSC_UPDATE _IOW('I', 0x29, ipu_csc_update)
+#define IPU_SELECT_MULTI_VDI_BUFFER _IOW('I', 0x2A, uint32_t)
int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
unsigned int output_frame_width,
diff --git a/include/linux/libata.h b/include/linux/libata.h
index e5b6e33c6571..d3f7cab4873e 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -190,6 +190,7 @@ enum {
ATA_FLAG_NO_POWEROFF_SPINDOWN = (1 << 11), /* don't spindown before poweroff */
ATA_FLAG_NO_HIBERNATE_SPINDOWN = (1 << 12), /* don't spindown before hibernation */
ATA_FLAG_DEBUGMSG = (1 << 13),
+ ATA_FLAG_FPDMA_AA = (1 << 14), /* driver supports Auto-Activate */
ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */
ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */
ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */
@@ -386,6 +387,7 @@ enum {
ATA_HORKAGE_FIRMWARE_WARN = (1 << 12), /* firmware update warning */
ATA_HORKAGE_1_5_GBPS = (1 << 13), /* force 1.5 Gbps */
ATA_HORKAGE_NOSETXFER = (1 << 14), /* skip SETXFER, SATA only */
+ ATA_HORKAGE_BROKEN_FPDMA_AA = (1 << 15), /* skip AA */
/* DMA mask for user DMA control: User visible values; DO NOT
renumber */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 9a72cc78e6b8..291bc1c9d0ed 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -710,6 +710,7 @@ static inline int shmem_lock(struct file *file, int lock,
}
#endif
struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags);
+void shmem_set_file(struct vm_area_struct *vma, struct file *file);
int shmem_zero_setup(struct vm_area_struct *);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 403aa505f27e..9167c389779e 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -40,8 +40,16 @@ struct mmc_csd {
};
struct mmc_ext_csd {
+ u8 rev;
+ unsigned int sa_timeout; /* Units: 100ns */
unsigned int hs_max_dtr;
unsigned int sectors;
+ unsigned int card_type;
+#define MMC_DDR_MODE_MASK (0x3<<2)
+ unsigned char boot_info;
+ unsigned char boot_size_mult;
+ unsigned char boot_config;
+ unsigned char boot_bus_width;
};
struct sd_scr {
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 7ac8b500d55c..e4898e9eeb59 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -139,6 +139,7 @@ extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);
extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
extern void mmc_release_host(struct mmc_host *host);
+extern int mmc_try_claim_host(struct mmc_host *host);
/**
* mmc_claim_host - exclusively claim a host
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 3e7615e9087e..289c17d3e705 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -13,6 +13,7 @@
#include <linux/leds.h>
#include <linux/mmc/core.h>
+#include <linux/mmc/pm.h>
struct mmc_ios {
unsigned int clock; /* clock rate */
@@ -42,6 +43,7 @@ struct mmc_ios {
#define MMC_BUS_WIDTH_1 0
#define MMC_BUS_WIDTH_4 2
#define MMC_BUS_WIDTH_8 3
+#define MMC_BUS_WIDTH_DDR 8
unsigned char timing; /* timing specification used */
@@ -51,6 +53,35 @@ struct mmc_ios {
};
struct mmc_host_ops {
+ /*
+ * Hosts that support power saving can use the 'enable' and 'disable'
+ * methods to exit and enter power saving states. 'enable' is called
+ * when the host is claimed and 'disable' is called (or scheduled with
+ * a delay) when the host is released. The 'disable' is scheduled if
+ * the disable delay set by 'mmc_set_disable_delay()' is non-zero,
+ * otherwise 'disable' is called immediately. 'disable' may be
+ * scheduled repeatedly, to permit ever greater power saving at the
+ * expense of ever greater latency to re-enable. Rescheduling is
+ * determined by the return value of the 'disable' method. A positive
+ * value gives the delay in milliseconds.
+ *
+ * In the case where a host function (like set_ios) may be called
+ * with or without the host claimed, enabling and disabling can be
+ * done directly and will nest correctly. Call 'mmc_host_enable()' and
+ * 'mmc_host_lazy_disable()' for this purpose, but note that these
+ * functions must be paired.
+ *
+ * Alternatively, 'mmc_host_enable()' may be paired with
+ * 'mmc_host_disable()' which calls 'disable' immediately. In this
+ * case the 'disable' method will be called with 'lazy' set to 0.
+ * This is mainly useful for error paths.
+ *
+ * Because lazy disable may be called from a work queue, the 'disable'
+ * method must claim the host when 'lazy' != 0, which will work
+ * correctly because recursion is detected and handled.
+ */
+ int (*enable)(struct mmc_host *host);
+ int (*disable)(struct mmc_host *host, int lazy);
void (*request)(struct mmc_host *host, struct mmc_request *req);
/*
* Avoid calling these three functions too often or in a "fast path",
@@ -90,6 +121,7 @@ struct mmc_host {
unsigned int f_min;
unsigned int f_max;
u32 ocr_avail;
+ struct notifier_block pm_notify;
#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
@@ -118,6 +150,12 @@ struct mmc_host {
#define MMC_CAP_SPI (1 << 4) /* Talks only SPI protocols */
#define MMC_CAP_NEEDS_POLL (1 << 5) /* Needs polling for card-detection */
#define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */
+#define MMC_CAP_DATA_DDR (1 << 7) /* Can the host do ddr transfers */
+#define MMC_CAP_DISABLE (1 << 7) /* Can the host be disabled */
+#define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */
+#define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */
+
+ mmc_pm_flag_t pm_caps; /* supported pm features */
/* host specific block data */
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
@@ -142,9 +180,19 @@ struct mmc_host {
unsigned int removed:1; /* host is being removed */
#endif
+ /* Only used with MMC_CAP_DISABLE */
+ int enabled; /* host is enabled */
+ int rescan_disable; /* disable card detection */
+ int nesting_cnt; /* "enable" nesting count */
+ int en_dis_recurs; /* detect recursion */
+ unsigned int disable_delay; /* disable delay in msecs */
+ struct delayed_work disable; /* disabling work */
+
struct mmc_card *card; /* device attached to this host */
wait_queue_head_t wq;
+ struct task_struct *claimer; /* task that has host claimed */
+ int claim_cnt; /* "claim" nesting count */
struct delayed_work detect;
@@ -155,6 +203,8 @@ struct mmc_host {
struct task_struct *sdio_irq_thread;
atomic_t sdio_irq_thread_abort;
+ mmc_pm_flag_t pm_flags; /* requested pm features */
+
#ifdef CONFIG_LEDS_TRIGGERS
struct led_trigger *led; /* activity led */
#endif
@@ -183,6 +233,9 @@ static inline void *mmc_priv(struct mmc_host *host)
extern int mmc_suspend_host(struct mmc_host *, pm_message_t);
extern int mmc_resume_host(struct mmc_host *);
+extern void mmc_power_save_host(struct mmc_host *host);
+extern void mmc_power_restore_host(struct mmc_host *host);
+
extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
@@ -197,5 +250,20 @@ struct regulator;
int mmc_regulator_get_ocrmask(struct regulator *supply);
int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit);
+int mmc_card_awake(struct mmc_host *host);
+int mmc_card_sleep(struct mmc_host *host);
+int mmc_card_can_sleep(struct mmc_host *host);
+
+int mmc_host_enable(struct mmc_host *host);
+int mmc_host_disable(struct mmc_host *host);
+int mmc_host_lazy_disable(struct mmc_host *host);
+int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
+
+static inline void mmc_set_disable_delay(struct mmc_host *host,
+ unsigned int disable_delay)
+{
+ host->disable_delay = disable_delay;
+}
+
#endif
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 14b81f3e5232..37a51b3122df 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -31,6 +31,7 @@
#define MMC_ALL_SEND_CID 2 /* bcr R2 */
#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
#define MMC_SET_DSR 4 /* bc [31:16] RCA */
+#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */
#define MMC_SWITCH 6 /* ac [31:0] See below R1b */
#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
#define MMC_SEND_EXT_CSD 8 /* adtc R1 */
@@ -249,11 +250,16 @@ struct _mmc_csd {
* EXT_CSD fields
*/
+#define EXT_CSD_BOOT_BUS_WIDTH 177 /* R/W */
+#define EXT_CSD_BOOT_CONFIG 179 /* R/W */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_HS_TIMING 185 /* R/W */
#define EXT_CSD_CARD_TYPE 196 /* RO */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
+#define EXT_CSD_S_A_TIMEOUT 217
+#define EXT_CSD_BOOT_SIZE_MULT 226 /* RO, 1 bytes */
+#define EXT_CSD_BOOT_INFO 228 /* RO, 1 bytes */
/*
* EXT_CSD field definitions
@@ -265,10 +271,36 @@ struct _mmc_csd {
#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */
#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */
+#define EXT_CSD_CARD_TYPE_DDR_52 (2<<1) /* Card can run at DDR 52MHz */
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
+#define EXT_CSD_BUS_WIDTH_4_DDR 5 /* Card is in 4 bit ddr mode */
+#define EXT_CSD_BUS_WIDTH_8_DDR 6 /* Card is in 8 bit ddr mode */
+
+#define EXT_CSD_BOOT_BUS_WIDTH_MASK (0x1F)
+#define EXT_CSD_BOOT_BUS_WIDTH_MODE_MASK (0x3 << 3)
+#define EXT_CSD_BOOT_BUS_WIDTH_MODE_SDR_NORMAL (0x0)
+#define EXT_CSD_BOOT_BUS_WIDTH_MODE_SDR_HIGH (0x1)
+#define EXT_CSD_BOOT_BUS_WIDTH_MODE_DDR (0x2)
+#define EXT_CSD_BOOT_BUS_WIDTH_RST_WIDTH (1 << 2)
+#define EXT_CSD_BOOT_BUS_WIDTH_WIDTH_MASK (0x3)
+#define EXT_CSD_BOOT_BUS_WIDTH_1_SDR_4_DDR (0x0)
+#define EXT_CSD_BOOT_BUS_WIDTH_4_SDR_4_DDR (0x1)
+#define EXT_CSD_BOOT_BUS_WIDTH_8_SDR_8_DDR (0x2)
+
+#define EXT_CSD_BOOT_ACK_ENABLE (0x1 << 6)
+#define EXT_CSD_BOOT_PARTITION_ENABLE_MASK (0x7 << 3)
+#define EXT_CSD_BOOT_PARTITION_DISABLE (0x0)
+#define EXT_CSD_BOOT_PARTITION_PART1 (0x1 << 3)
+#define EXT_CSD_BOOT_PARTITION_PART2 (0x2 << 3)
+#define EXT_CSD_BOOT_PARTITION_USER (0x7 << 3)
+
+#define EXT_CSD_BOOT_PARTITION_ACCESS_MASK (0x7)
+#define EXT_CSD_BOOT_PARTITION_ACCESS_DISABLE (0x0)
+#define EXT_CSD_BOOT_PARTITION_ACCESS_PART1 (0x1)
+#define EXT_CSD_BOOT_PARTITION_ACCESS_PART2 (0x2)
/*
* MMC_SWITCH access modes
diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h
index 451bdfc85830..51332c5bc2ef 100644
--- a/include/linux/mmc/sdio_func.h
+++ b/include/linux/mmc/sdio_func.h
@@ -15,6 +15,8 @@
#include <linux/device.h>
#include <linux/mod_devicetable.h>
+#include <linux/mmc/pm.h>
+
struct mmc_card;
struct sdio_func;
@@ -150,5 +152,8 @@ extern unsigned char sdio_f0_readb(struct sdio_func *func,
extern void sdio_f0_writeb(struct sdio_func *func, unsigned char b,
unsigned int addr, int *err_ret);
+extern mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func);
+extern int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags);
+
#endif
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index ce38f1caa5e1..844d77ddfb34 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -100,6 +100,7 @@ struct __fat_dirent {
/* <linux/videotext.h> has used 0x72 ('r') in collision, so skip a few */
#define FAT_IOCTL_GET_ATTRIBUTES _IOR('r', 0x10, __u32)
#define FAT_IOCTL_SET_ATTRIBUTES _IOW('r', 0x11, __u32)
+#define VFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32)
struct fat_boot_sector {
__u8 ignored[3]; /* Boot strap short or near jump */
@@ -137,6 +138,17 @@ struct fat_boot_fsinfo {
__le32 reserved2[4];
};
+struct fat_boot_bsx {
+ __u8 drive; /* drive number */
+ __u8 reserved1;
+ __u8 signature; /* extended boot signature */
+ __u8 vol_id[4]; /* volume ID */
+ __u8 vol_label[11]; /* volume label */
+ __u8 type[8]; /* file system type */
+};
+#define FAT16_BSX_OFFSET 36 /* offset of fat_boot_bsx in FAT12 and FAT16 */
+#define FAT32_BSX_OFFSET 64 /* offset of fat_boot_bsx in FAT32 */
+
struct msdos_dir_entry {
__u8 name[MSDOS_NAME];/* name and extension */
__u8 attr; /* attribute bits */
diff --git a/include/linux/mxcfb.h b/include/linux/mxcfb.h
index f0ea365753a9..0f92ad04942c 100644
--- a/include/linux/mxcfb.h
+++ b/include/linux/mxcfb.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -58,6 +58,58 @@ struct mxcfb_gamma {
int slopek[16];
};
+struct mxcfb_rect {
+ __u32 top;
+ __u32 left;
+ __u32 width;
+ __u32 height;
+};
+
+#define GRAYSCALE_8BIT 0x1
+#define GRAYSCALE_8BIT_INVERTED 0x2
+
+#define AUTO_UPDATE_MODE_REGION_MODE 0
+#define AUTO_UPDATE_MODE_AUTOMATIC_MODE 1
+
+#define UPDATE_MODE_PARTIAL 0x0
+#define UPDATE_MODE_FULL 0x1
+
+#define WAVEFORM_MODE_AUTO 257
+
+#define TEMP_USE_AMBIENT 0x1000
+
+#define FB_POWERDOWN_DISABLE -1
+
+struct mxcfb_alt_buffer_data {
+ __u32 phys_addr;
+ __u32 width; /* width of entire buffer */
+ __u32 height; /* height of entire buffer */
+ struct mxcfb_rect alt_update_region; /* region within buffer to update */
+};
+
+struct mxcfb_update_data {
+ struct mxcfb_rect update_region;
+ __u32 waveform_mode;
+ __u32 update_mode;
+ __u32 update_marker;
+ int temp;
+ int use_alt_buffer;
+ struct mxcfb_alt_buffer_data alt_buffer_data;
+};
+
+/*
+ * Structure used to define waveform modes for driver
+ * Needed for driver to perform auto-waveform selection
+ */
+struct mxcfb_waveform_modes {
+ int mode_init;
+ int mode_du;
+ int mode_gc4;
+ int mode_gc8;
+ int mode_gc16;
+ int mode_gc32;
+};
+
#define MXCFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t)
#define MXCFB_SET_GBL_ALPHA _IOW('F', 0x21, struct mxcfb_gbl_alpha)
#define MXCFB_SET_CLR_KEY _IOW('F', 0x22, struct mxcfb_color_key)
@@ -66,6 +118,18 @@ struct mxcfb_gamma {
#define MXCFB_SET_LOC_ALPHA _IOWR('F', 0x26, struct mxcfb_loc_alpha)
#define MXCFB_SET_LOC_ALP_BUF _IOW('F', 0x27, unsigned long)
#define MXCFB_SET_GAMMA _IOW('F', 0x28, struct mxcfb_gamma)
+#define MXCFB_GET_FB_IPU_DI _IOR('F', 0x29, u_int32_t)
+#define MXCFB_GET_DIFMT _IOR('F', 0x2A, u_int32_t)
+#define MXCFB_GET_FB_BLANK _IOR('F', 0x2B, u_int32_t)
+
+/* IOCTLs for E-ink panel updates */
+#define MXCFB_SET_WAVEFORM_MODES _IOW('F', 0x2B, struct mxcfb_waveform_modes)
+#define MXCFB_SET_TEMPERATURE _IOW('F', 0x2C, int32_t)
+#define MXCFB_SET_AUTO_UPDATE_MODE _IOW('F', 0x2D, __u32)
+#define MXCFB_SEND_UPDATE _IOW('F', 0x2E, struct mxcfb_update_data)
+#define MXCFB_WAIT_FOR_UPDATE_COMPLETE _IOW('F', 0x2F, __u32)
+#define MXCFB_SET_PWRDOWN_DELAY _IOW('F', 0x30, int32_t)
+#define MXCFB_GET_PWRDOWN_DELAY _IOR('F', 0x31, int32_t)
#ifdef __KERNEL__
@@ -78,15 +142,9 @@ enum {
MXCFB_REFRESH_PARTIAL,
};
-struct mxcfb_rect {
- u32 top;
- u32 left;
- u32 width;
- u32 height;
-};
-
int mxcfb_set_refresh_mode(struct fb_info *fbi, int mode,
struct mxcfb_rect *update_region);
+int mxc_elcdif_frame_addr_setup(dma_addr_t phys);
#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/phy.h b/include/linux/phy.h
index b1368b8f6572..6a7eb402165d 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -447,6 +447,7 @@ struct phy_device* get_phy_device(struct mii_bus *bus, int addr);
int phy_device_register(struct phy_device *phy);
int phy_clear_interrupt(struct phy_device *phydev);
int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
+int phy_init_hw(struct phy_device *phydev);
int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
u32 flags, phy_interface_t interface);
struct phy_device * phy_attach(struct net_device *dev,
@@ -484,6 +485,7 @@ void phy_driver_unregister(struct phy_driver *drv);
int phy_driver_register(struct phy_driver *new_driver);
void phy_prepare_link(struct phy_device *phydev,
void (*adjust_link)(struct net_device *));
+void phy_state_machine(struct work_struct *work);
void phy_start_machine(struct phy_device *phydev,
void (*handler)(struct net_device *));
void phy_stop_machine(struct phy_device *phydev);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 0f1ea4a66957..5c6993ea13c5 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1665,6 +1665,9 @@ extern cputime_t task_utime(struct task_struct *p);
extern cputime_t task_stime(struct task_struct *p);
extern cputime_t task_gtime(struct task_struct *p);
+extern int task_free_register(struct notifier_block *n);
+extern int task_free_unregister(struct notifier_block *n);
+
/*
* Per process flags
*/
diff --git a/include/linux/sockios.h b/include/linux/sockios.h
index 241f179347d9..f4fa1a164c74 100644
--- a/include/linux/sockios.h
+++ b/include/linux/sockios.h
@@ -65,6 +65,7 @@
#define SIOCDIFADDR 0x8936 /* delete PA address */
#define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */
#define SIOCGIFCOUNT 0x8938 /* get number of devices */
+#define SIOCKILLADDR 0x8939 /* kill sockets with this local addr */
#define SIOCGIFBR 0x8940 /* Bridging support */
#define SIOCSIFBR 0x8941 /* Set bridging options */
diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h
index 51948eb6927a..c87aa2680947 100644
--- a/include/linux/spi/ads7846.h
+++ b/include/linux/spi/ads7846.h
@@ -5,36 +5,17 @@
*
* It's OK if the min/max values are zero.
*/
-enum ads7846_filter {
- ADS7846_FILTER_OK,
- ADS7846_FILTER_REPEAT,
- ADS7846_FILTER_IGNORE,
-};
struct ads7846_platform_data {
u16 model; /* 7843, 7845, 7846. */
u16 vref_delay_usecs; /* 0 for external vref; etc */
- u16 vref_mv; /* external vref value, milliVolts */
- bool keep_vref_on; /* set to keep vref on for differential
- * measurements as well */
- bool swap_xy; /* swap x and y axes */
-
- /* Settling time of the analog signals; a function of Vcc and the
- * capacitance on the X/Y drivers. If set to non-zero, two samples
- * are taken with settle_delay us apart, and the second one is used.
- * ~150 uSec with 0.01uF caps.
- */
- u16 settle_delay_usecs;
-
- /* If set to non-zero, after samples are taken this delay is applied
- * and penirq is rechecked, to help avoid false events. This value
- * is affected by the material used to build the touch layer.
- */
- u16 penirq_recheck_delay_usecs;
-
u16 x_plate_ohms;
u16 y_plate_ohms;
+ u8 buflen;
+ u8 skip_samples;
+ u16 rotate;
+
u16 x_min, x_max;
u16 y_min, y_max;
u16 pressure_min, pressure_max;
@@ -44,14 +25,5 @@ struct ads7846_platform_data {
u16 debounce_tol; /* tolerance used for filtering */
u16 debounce_rep; /* additional consecutive good readings
* required after the first two */
- int gpio_pendown; /* the GPIO used to decide the pendown
- * state if get_pendown_state == NULL
- */
int (*get_pendown_state)(void);
- int (*filter_init) (struct ads7846_platform_data *pdata,
- void **filter_data);
- int (*filter) (void *filter_data, int data_idx, int *val);
- void (*filter_cleanup)(void *filter_data);
- void (*wait_for_sync)(void);
};
-
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 4f6bb3d2160e..8f33ae3e00f3 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -100,6 +100,7 @@ struct usb_function {
struct usb_descriptor_header **hs_descriptors;
struct usb_configuration *config;
+ int hidden;
/* REVISIT: bind() functions can be marked __init, which
* makes trouble for section mismatch analysis. See if
diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h
index fbf585561570..08d9ad2947a8 100644
--- a/include/media/v4l2-int-device.h
+++ b/include/media/v4l2-int-device.h
@@ -186,6 +186,8 @@ enum v4l2_int_ioctl_num {
vidioc_int_querystd_num,
vidioc_int_s_std_num,
vidioc_int_s_video_routing_num,
+ vidioc_int_g_register_num,
+ vidioc_int_s_register_num,
/*
*
@@ -290,6 +292,8 @@ V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *);
V4L2_INT_WRAPPER_1(querystd, v4l2_std_id, *);
V4L2_INT_WRAPPER_1(s_std, v4l2_std_id, *);
V4L2_INT_WRAPPER_1(s_video_routing, struct v4l2_routing, *);
+V4L2_INT_WRAPPER_1(g_register, struct v4l2_dbg_register , *);
+V4L2_INT_WRAPPER_1(s_register, struct v4l2_dbg_register , *);
V4L2_INT_WRAPPER_0(dev_init);
V4L2_INT_WRAPPER_0(dev_exit);
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index ed3aea1605e8..59cdece3a1a4 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -139,8 +139,10 @@ enum {
#define ESCO_2EV5 0x0100
#define ESCO_3EV5 0x0200
-#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3)
-#define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5)
+#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3)
+#define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5)
+#define ALL_ESCO_MASK (SCO_ESCO_MASK | ESCO_EV3 | ESCO_EV4 | ESCO_EV5 | \
+ EDR_ESCO_MASK)
/* ACL flags */
#define ACL_CONT 0x01
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index c4ca4228b083..2b8fc2c58b14 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -325,12 +325,15 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
void hci_add_sco(struct hci_conn *conn, __u16 handle);
void hci_setup_sync(struct hci_conn *conn, __u16 handle);
-struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
+struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type,
+ __u16 pkt_type, bdaddr_t *dst);
int hci_conn_del(struct hci_conn *conn);
void hci_conn_hash_flush(struct hci_dev *hdev);
void hci_conn_check_pending(struct hci_dev *hdev);
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type);
+struct hci_conn *hci_connect(struct hci_dev *hdev, int type,
+ __u16 pkt_type, bdaddr_t *dst,
+ __u8 sec_level, __u8 auth_type);
int hci_conn_check_link_mode(struct hci_conn *conn);
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type);
int hci_conn_change_link_key(struct hci_conn *conn);
diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h
index e28a2a771471..924338ac3223 100644
--- a/include/net/bluetooth/sco.h
+++ b/include/net/bluetooth/sco.h
@@ -37,6 +37,7 @@
struct sockaddr_sco {
sa_family_t sco_family;
bdaddr_t sco_bdaddr;
+ __u16 sco_pkt_type;
};
/* SCO socket options */
@@ -72,7 +73,8 @@ struct sco_conn {
struct sco_pinfo {
struct bt_sock bt;
- __u32 flags;
+ __u16 pkt_type;
+
struct sco_conn *conn;
};
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 88af84306471..eb2ed40659c6 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1396,6 +1396,8 @@ extern struct sk_buff **tcp4_gro_receive(struct sk_buff **head,
extern int tcp_gro_complete(struct sk_buff *skb);
extern int tcp4_gro_complete(struct sk_buff *skb);
+extern void tcp_v4_nuke_addr(__u32 saddr);
+
#ifdef CONFIG_PROC_FS
extern int tcp4_proc_init(void);
extern void tcp4_proc_exit(void);
diff --git a/init/Kconfig b/init/Kconfig
index 3f7e60995c80..419134cfc80d 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -976,6 +976,15 @@ config EVENT_PROFILE
endmenu
+config ASHMEM
+ bool "Enable the Anonymous Shared Memory Subsystem"
+ default n
+ depends on SHMEM || TINY_SHMEM
+ help
+ The ashmem subsystem is a new shared memory allocator, similar to
+ POSIX SHM but with different behavior and sporting a simpler
+ file-based API.
+
config VM_EVENT_COUNTERS
default y
bool "Enable VM event counters for /proc/vmstat" if EMBEDDED
diff --git a/kernel/fork.c b/kernel/fork.c
index e6c04d462ab2..4c21988d6195 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -136,6 +136,9 @@ struct kmem_cache *vm_area_cachep;
/* SLAB cache for mm_struct structures (tsk->mm) */
static struct kmem_cache *mm_cachep;
+/* Notifier list called when a task struct is freed */
+static ATOMIC_NOTIFIER_HEAD(task_free_notifier);
+
void free_task(struct task_struct *tsk)
{
prop_local_destroy_single(&tsk->dirties);
@@ -146,6 +149,18 @@ void free_task(struct task_struct *tsk)
}
EXPORT_SYMBOL(free_task);
+int task_free_register(struct notifier_block *n)
+{
+ return atomic_notifier_chain_register(&task_free_notifier, n);
+}
+EXPORT_SYMBOL(task_free_register);
+
+int task_free_unregister(struct notifier_block *n)
+{
+ return atomic_notifier_chain_unregister(&task_free_notifier, n);
+}
+EXPORT_SYMBOL(task_free_unregister);
+
void __put_task_struct(struct task_struct *tsk)
{
WARN_ON(!tsk->exit_state);
@@ -156,6 +171,7 @@ void __put_task_struct(struct task_struct *tsk)
put_cred(tsk->cred);
delayacct_tsk_free(tsk);
+ atomic_notifier_call_chain(&task_free_notifier, 0, tsk);
if (!profile_handoff_task(tsk))
free_task(tsk);
}
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 065205bdd920..e8108a1a0eaf 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -274,6 +274,7 @@ struct irq_desc *irq_to_desc(unsigned int irq)
{
return (irq < NR_IRQS) ? irq_desc + irq : NULL;
}
+EXPORT_SYMBOL(irq_to_desc);
struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node)
{
@@ -368,9 +369,6 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
irqreturn_t ret, retval = IRQ_NONE;
unsigned int status = 0;
- if (!(action->flags & IRQF_DISABLED))
- local_irq_enable_in_hardirq();
-
do {
trace_irq_handler_entry(irq, action);
ret = action->handler(irq, action->dev_id);
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 72067cbdb37f..bd007aa74549 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -119,6 +119,73 @@ config SUSPEND_FREEZER
config HIBERNATION_NVS
bool
+config HAS_WAKELOCK
+ bool
+
+config HAS_EARLYSUSPEND
+ bool
+
+config WAKELOCK
+ bool "Wake lock"
+ depends on PM && RTC_CLASS
+ default n
+ select HAS_WAKELOCK
+ ---help---
+ Enable wakelocks. When user space request a sleep state the
+ sleep request will be delayed until no wake locks are held.
+
+config WAKELOCK_STAT
+ bool "Wake lock stats"
+ depends on WAKELOCK
+ default y
+ ---help---
+ Report wake lock stats in /proc/wakelocks
+
+config USER_WAKELOCK
+ bool "Userspace wake locks"
+ depends on WAKELOCK
+ default y
+ ---help---
+ User-space wake lock api. Write "lockname" or "lockname timeout"
+ to /sys/power/wake_lock lock and if needed create a wake lock.
+ Write "lockname" to /sys/power/wake_unlock to unlock a user wake
+ lock.
+
+config EARLYSUSPEND
+ bool "Early suspend"
+ depends on WAKELOCK
+ default y
+ select HAS_EARLYSUSPEND
+ ---help---
+ Call early suspend handlers when the user requested sleep state
+ changes.
+
+choice
+ prompt "User-space screen access"
+ default FB_EARLYSUSPEND if !FRAMEBUFFER_CONSOLE
+ default CONSOLE_EARLYSUSPEND
+ depends on HAS_EARLYSUSPEND
+
+ config NO_USER_SPACE_SCREEN_ACCESS_CONTROL
+ bool "None"
+
+ config CONSOLE_EARLYSUSPEND
+ bool "Console switch on early-suspend"
+ depends on HAS_EARLYSUSPEND && VT
+ ---help---
+ Register early suspend handler to perform a console switch to
+ when user-space should stop drawing to the screen and a switch
+ back when it should resume.
+
+ config FB_EARLYSUSPEND
+ bool "Sysfs interface"
+ depends on HAS_EARLYSUSPEND
+ ---help---
+ Register early suspend handler that notifies and waits for
+ user-space through sysfs when user-space should stop drawing
+ to the screen and notifies user-space when it should resume.
+endchoice
+
config HIBERNATION
bool "Hibernation (aka 'suspend to disk')"
depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index c3b81c30e5d5..058ec85a98bd 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -12,3 +12,8 @@ obj-$(CONFIG_HIBERNATION) += swsusp.o hibernate.o snapshot.o swap.o user.o
obj-$(CONFIG_HIBERNATION_NVS) += hibernate_nvs.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
+obj-$(CONFIG_WAKELOCK) += wakelock.o
+obj-$(CONFIG_USER_WAKELOCK) += userwakelock.o
+obj-$(CONFIG_EARLYSUSPEND) += earlysuspend.o
+obj-$(CONFIG_CONSOLE_EARLYSUSPEND) += consoleearlysuspend.o
+obj-$(CONFIG_FB_EARLYSUSPEND) += fbearlysuspend.o
diff --git a/kernel/power/main.c b/kernel/power/main.c
index f710e36930cc..ef94a083302f 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -146,7 +146,11 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
#ifdef CONFIG_SUSPEND
+#ifdef CONFIG_EARLYSUSPEND
+ suspend_state_t state = PM_SUSPEND_ON;
+#else
suspend_state_t state = PM_SUSPEND_STANDBY;
+#endif
const char * const *s;
#endif
char *p;
@@ -168,8 +172,15 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
break;
}
if (state < PM_SUSPEND_MAX && *s)
+#ifdef CONFIG_EARLYSUSPEND
+ if (state == PM_SUSPEND_ON || valid_state(state)) {
+ error = 0;
+ request_suspend_state(state);
+ }
+#else
error = enter_state(state);
#endif
+#endif
Exit:
return error ? error : n;
@@ -202,6 +213,11 @@ pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
power_attr(pm_trace);
#endif /* CONFIG_PM_TRACE */
+#ifdef CONFIG_USER_WAKELOCK
+power_attr(wake_lock);
+power_attr(wake_unlock);
+#endif
+
static struct attribute * g[] = {
&state_attr.attr,
#ifdef CONFIG_PM_TRACE
@@ -210,6 +226,10 @@ static struct attribute * g[] = {
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG)
&pm_test_attr.attr,
#endif
+#ifdef CONFIG_USER_WAKELOCK
+ &wake_lock_attr.attr,
+ &wake_unlock_attr.attr,
+#endif
NULL,
};
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 26d5a26f82e3..a665c1e4e597 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -236,3 +236,27 @@ static inline void suspend_thaw_processes(void)
{
}
#endif
+
+#ifdef CONFIG_WAKELOCK
+/* kernel/power/wakelock.c */
+extern struct workqueue_struct *suspend_work_queue;
+extern struct wake_lock main_wake_lock;
+extern suspend_state_t requested_suspend_state;
+#endif
+
+#ifdef CONFIG_USER_WAKELOCK
+ssize_t wake_lock_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf);
+ssize_t wake_lock_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n);
+ssize_t wake_unlock_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf);
+ssize_t wake_unlock_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n);
+#endif
+
+#ifdef CONFIG_EARLYSUSPEND
+/* kernel/power/earlysuspend.c */
+void request_suspend_state(suspend_state_t state);
+suspend_state_t get_suspend_state(void);
+#endif
diff --git a/kernel/power/process.c b/kernel/power/process.c
index da2072d73811..d366c35f8ba0 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/freezer.h>
+#include <linux/wakelock.h>
/*
* Timeout for stopping processes
@@ -36,6 +37,7 @@ static int try_to_freeze_tasks(bool sig_only)
struct timeval start, end;
u64 elapsed_csecs64;
unsigned int elapsed_csecs;
+ unsigned int wakeup = 0;
do_gettimeofday(&start);
@@ -62,6 +64,12 @@ static int try_to_freeze_tasks(bool sig_only)
} while_each_thread(g, p);
read_unlock(&tasklist_lock);
yield(); /* Yield is okay here */
+#ifdef CONFIG_WAKELOCK
+ if (todo && has_wake_lock(WAKE_LOCK_SUSPEND)) {
+ wakeup = 1;
+ break;
+ }
+#endif
if (time_after(jiffies, end_time))
break;
} while (todo);
@@ -77,11 +85,18 @@ static int try_to_freeze_tasks(bool sig_only)
* and caller must call thaw_processes() if something fails),
* but it cleans up leftover PF_FREEZE requests.
*/
- printk("\n");
- printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds "
- "(%d tasks refusing to freeze):\n",
- elapsed_csecs / 100, elapsed_csecs % 100, todo);
- show_state();
+ if(wakeup) {
+ printk("\n");
+ printk(KERN_ERR "Freezing of %s aborted\n",
+ sig_only ? "user space " : "tasks ");
+ }
+ else {
+ printk("\n");
+ printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds "
+ "(%d tasks refusing to freeze):\n",
+ elapsed_csecs / 100, elapsed_csecs % 100, todo);
+ show_state();
+ }
read_lock(&tasklist_lock);
do_each_thread(g, p) {
task_lock(p);
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 6f10dfc2d3e9..cd515ba1c8ce 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -19,6 +19,9 @@
#include "power.h"
const char *const pm_states[PM_SUSPEND_MAX] = {
+#ifdef CONFIG_EARLYSUSPEND
+ [PM_SUSPEND_ON] = "on",
+#endif
[PM_SUSPEND_STANDBY] = "standby",
[PM_SUSPEND_MEM] = "mem",
};
diff --git a/mm/Makefile b/mm/Makefile
index 5e0bd6426693..f4e009cba6a5 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_HUGETLBFS) += hugetlb.o
obj-$(CONFIG_NUMA) += mempolicy.o
obj-$(CONFIG_SPARSEMEM) += sparse.o
obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o
+obj-$(CONFIG_ASHMEM) += ashmem.o
obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o
obj-$(CONFIG_SLOB) += slob.o
obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
diff --git a/mm/shmem.c b/mm/shmem.c
index d713239ce2ce..fb7861108d31 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2668,6 +2668,14 @@ put_memory:
}
EXPORT_SYMBOL_GPL(shmem_file_setup);
+void shmem_set_file(struct vm_area_struct *vma, struct file *file)
+{
+ if (vma->vm_file)
+ fput(vma->vm_file);
+ vma->vm_file = file;
+ vma->vm_ops = &shmem_vm_ops;
+}
+
/**
* shmem_zero_setup - setup a shared anonymous mapping
* @vma: the vma to be mmapped is prepared by do_mmap_pgoff
@@ -2680,11 +2688,8 @@ int shmem_zero_setup(struct vm_area_struct *vma)
file = shmem_file_setup("dev/zero", size, vma->vm_flags);
if (IS_ERR(file))
return PTR_ERR(file);
+ shmem_set_file(vma, file);
- if (vma->vm_file)
- fput(vma->vm_file);
- vma->vm_file = file;
- vma->vm_ops = &shmem_vm_ops;
return 0;
}
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index fa47d5d84f5c..6b25e6eaed19 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -196,7 +196,8 @@ static void hci_conn_idle(unsigned long arg)
hci_conn_enter_sniff_mode(conn);
}
-struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
+struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type,
+ __u16 pkt_type, bdaddr_t *dst)
{
struct hci_conn *conn;
@@ -220,14 +221,22 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
break;
case SCO_LINK:
- if (lmp_esco_capable(hdev))
- conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
- (hdev->esco_type & EDR_ESCO_MASK);
- else
- conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
- break;
+ if (!pkt_type)
+ pkt_type = SCO_ESCO_MASK;
case ESCO_LINK:
- conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
+ if (!pkt_type)
+ pkt_type = ALL_ESCO_MASK;
+ if (lmp_esco_capable(hdev)) {
+ /* HCI Setup Synchronous Connection Command uses
+ reverse logic on the EDR_ESCO_MASK bits */
+ conn->pkt_type = (pkt_type ^ EDR_ESCO_MASK) &
+ hdev->esco_type;
+ } else {
+ /* Legacy HCI Add Sco Connection Command uses a
+ shifted bitmask */
+ conn->pkt_type = (pkt_type << 5) & hdev->pkt_type &
+ SCO_PTYPE_MASK;
+ }
break;
}
@@ -337,7 +346,9 @@ EXPORT_SYMBOL(hci_get_route);
/* Create SCO or ACL connection.
* Device _must_ be locked */
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
+struct hci_conn *hci_connect(struct hci_dev *hdev, int type,
+ __u16 pkt_type, bdaddr_t *dst,
+ __u8 sec_level, __u8 auth_type)
{
struct hci_conn *acl;
struct hci_conn *sco;
@@ -345,7 +356,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
BT_DBG("%s dst %s", hdev->name, batostr(dst));
if (!(acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
- if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
+ if (!(acl = hci_conn_add(hdev, ACL_LINK, 0, dst)))
return NULL;
}
@@ -361,7 +372,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
return acl;
if (!(sco = hci_conn_hash_lookup_ba(hdev, type, dst))) {
- if (!(sco = hci_conn_add(hdev, type, dst))) {
+ if (!(sco = hci_conn_add(hdev, type, pkt_type, dst))) {
hci_conn_put(acl);
return NULL;
}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 184ba0a88ec0..39f13cc05e5c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -579,7 +579,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
}
} else {
if (!conn) {
- conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr);
+ conn = hci_conn_add(hdev, ACL_LINK, 0, &cp->bdaddr);
if (conn) {
conn->out = 1;
conn->link_mode |= HCI_LM_MASTER;
@@ -963,7 +963,9 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
if (!conn) {
- if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) {
+ /* pkt_type not yet used for incoming connections */
+ if (!(conn = hci_conn_add(hdev, ev->link_type, 0,
+ &ev->bdaddr))) {
BT_ERR("No memmory for new connection");
hci_dev_unlock(hdev);
return;
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index bd0a4c1bced0..d780295364da 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -403,7 +403,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
struct sock *parent = bt_sk(sk)->parent;
rsp.result = cpu_to_le16(L2CAP_CR_PEND);
rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
- parent->sk_data_ready(parent, 0);
+ if (parent)
+ parent->sk_data_ready(parent, 0);
} else {
sk->sk_state = BT_CONFIG;
@@ -896,7 +897,7 @@ static int l2cap_do_connect(struct sock *sk)
}
}
- hcon = hci_connect(hdev, ACL_LINK, dst,
+ hcon = hci_connect(hdev, ACL_LINK, 0, dst,
l2cap_pi(sk)->sec_level, auth_type);
if (!hcon)
goto done;
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 94b3388c188b..4e6e1c637de9 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -448,7 +448,6 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
break;
case BT_OPEN:
- case BT_CONNECT2:
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
rfcomm_schedule(RFCOMM_SCHED_AUTH);
@@ -1194,8 +1193,6 @@ void rfcomm_dlc_accept(struct rfcomm_dlc *d)
rfcomm_send_ua(d->session, d->dlci);
- rfcomm_dlc_clear_timer(d);
-
rfcomm_dlc_lock(d);
d->state = BT_CONNECTED;
d->state_change(d, 0);
@@ -1213,11 +1210,6 @@ static void rfcomm_check_accept(struct rfcomm_dlc *d)
if (d->defer_setup) {
set_bit(RFCOMM_DEFER_SETUP, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
-
- rfcomm_dlc_lock(d);
- d->state = BT_CONNECT2;
- d->state_change(d, 0);
- rfcomm_dlc_unlock(d);
} else
rfcomm_dlc_accept(d);
} else {
@@ -1759,11 +1751,6 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
if (d->defer_setup) {
set_bit(RFCOMM_DEFER_SETUP, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
-
- rfcomm_dlc_lock(d);
- d->state = BT_CONNECT2;
- d->state_change(d, 0);
- rfcomm_dlc_unlock(d);
} else
rfcomm_dlc_accept(d);
}
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 51ae0c3e470a..98d9d07ddbff 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -176,6 +176,7 @@ static int sco_connect(struct sock *sk)
{
bdaddr_t *src = &bt_sk(sk)->src;
bdaddr_t *dst = &bt_sk(sk)->dst;
+ __u16 pkt_type = sco_pi(sk)->pkt_type;
struct sco_conn *conn;
struct hci_conn *hcon;
struct hci_dev *hdev;
@@ -192,10 +193,13 @@ static int sco_connect(struct sock *sk)
if (lmp_esco_capable(hdev) && !disable_esco)
type = ESCO_LINK;
- else
+ else {
type = SCO_LINK;
+ pkt_type &= SCO_ESCO_MASK;
+ }
- hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
+ hcon = hci_connect(hdev, type, pkt_type, dst,
+ BT_SECURITY_LOW, HCI_AT_NO_BONDING);
if (!hcon)
goto done;
@@ -456,18 +460,22 @@ static int sco_sock_create(struct net *net, struct socket *sock, int protocol)
return 0;
}
-static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{
- struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
+ struct sockaddr_sco sa;
struct sock *sk = sock->sk;
- bdaddr_t *src = &sa->sco_bdaddr;
- int err = 0;
+ bdaddr_t *src = &sa.sco_bdaddr;
+ int len, err = 0;
- BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
+ BT_DBG("sk %p %s", sk, batostr(&sa.sco_bdaddr));
if (!addr || addr->sa_family != AF_BLUETOOTH)
return -EINVAL;
+ memset(&sa, 0, sizeof(sa));
+ len = min_t(unsigned int, sizeof(sa), alen);
+ memcpy(&sa, addr, len);
+
lock_sock(sk);
if (sk->sk_state != BT_OPEN) {
@@ -481,7 +489,8 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
err = -EADDRINUSE;
} else {
/* Save source address */
- bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr);
+ bacpy(&bt_sk(sk)->src, &sa.sco_bdaddr);
+ sco_pi(sk)->pkt_type = sa.sco_pkt_type;
sk->sk_state = BT_BOUND;
}
@@ -494,26 +503,34 @@ done:
static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
{
- struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
struct sock *sk = sock->sk;
- int err = 0;
-
+ struct sockaddr_sco sa;
+ int len, err = 0;
BT_DBG("sk %p", sk);
- if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco))
+ if (!addr || addr->sa_family != AF_BLUETOOTH)
return -EINVAL;
- if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
- return -EBADFD;
-
- if (sk->sk_type != SOCK_SEQPACKET)
- return -EINVAL;
+ memset(&sa, 0, sizeof(sa));
+ len = min_t(unsigned int, sizeof(sa), alen);
+ memcpy(&sa, addr, len);
lock_sock(sk);
+ if (sk->sk_type != SOCK_SEQPACKET) {
+ err = -EINVAL;
+ goto done;
+ }
+
+ if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
+ err = -EBADFD;
+ goto done;
+ }
+
/* Set destination address and psm */
- bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr);
+ bacpy(&bt_sk(sk)->dst, &sa.sco_bdaddr);
+ sco_pi(sk)->pkt_type = sa.sco_pkt_type;
if ((err = sco_connect(sk)))
goto done;
@@ -619,6 +636,7 @@ static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len
bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst);
else
bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src);
+ sa->sco_pkt_type = sco_pi(sk)->pkt_type;
return 0;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index f956b9cbe963..ec28414f3564 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4345,6 +4345,12 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
default:
if ((cmd >= SIOCDEVPRIVATE &&
cmd <= SIOCDEVPRIVATE + 15) ||
+
+#if defined(CONFIG_FEC_L2SWITCH)
+ (cmd >= 0x9101 &&
+ cmd <= 0x92ff) ||
+#endif
+
cmd == SIOCBONDENSLAVE ||
cmd == SIOCBONDRELEASE ||
cmd == SIOCBONDSETHWADDR ||
@@ -4537,6 +4543,10 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
*/
default:
if (cmd == SIOCWANDEV ||
+#if defined(CONFIG_FEC_L2SWITCH)
+ (cmd >= 0x9101 &&
+ cmd <= 0x92ff) ||
+#endif
(cmd >= SIOCDEVPRIVATE &&
cmd <= SIOCDEVPRIVATE + 15)) {
dev_load(net, ifr.ifr_name);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 566ea6c4321d..3b478b320ad5 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -257,6 +257,7 @@ static inline int inet_netns_ok(struct net *net, int protocol)
return ipprot->netns_ok;
}
+
/*
* Create an inet socket.
*/
@@ -825,6 +826,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCSIFPFLAGS:
case SIOCGIFPFLAGS:
case SIOCSIFFLAGS:
+ case SIOCKILLADDR:
err = devinet_ioctl(net, cmd, (void __user *)arg);
break;
default:
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 3863c3a4223f..11b2ea9d2a56 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -57,6 +57,7 @@
#include <net/arp.h>
#include <net/ip.h>
+#include <net/tcp.h>
#include <net/route.h>
#include <net/ip_fib.h>
#include <net/rtnetlink.h>
@@ -631,6 +632,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
case SIOCSIFBRDADDR: /* Set the broadcast address */
case SIOCSIFDSTADDR: /* Set the destination address */
case SIOCSIFNETMASK: /* Set the netmask for the interface */
+ case SIOCKILLADDR: /* Nuke all sockets on this address */
ret = -EACCES;
if (!capable(CAP_NET_ADMIN))
goto out;
@@ -680,7 +682,8 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
}
ret = -EADDRNOTAVAIL;
- if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
+ if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS
+ && cmd != SIOCKILLADDR)
goto done;
switch (cmd) {
@@ -804,6 +807,10 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
inet_insert_ifa(ifa);
}
break;
+ case SIOCKILLADDR: /* Nuke all connections on this address */
+ ret = 0;
+ tcp_v4_nuke_addr(sin->sin_addr.s_addr);
+ break;
}
done:
rtnl_unlock();
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 6d88219c5e22..770fd759a6e9 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1846,6 +1846,49 @@ void tcp_v4_destroy_sock(struct sock *sk)
EXPORT_SYMBOL(tcp_v4_destroy_sock);
+/*
+ * tcp_v4_nuke_addr - destroy all sockets on the given local address
+ */
+void tcp_v4_nuke_addr(__u32 saddr)
+{
+ unsigned int bucket;
+
+ for (bucket = 0; bucket < tcp_hashinfo.ehash_size; bucket++) {
+ struct hlist_nulls_node *node;
+ struct sock *sk;
+ spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, bucket);
+
+restart:
+ spin_lock_bh(lock);
+ sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) {
+ struct inet_sock *inet = inet_sk(sk);
+
+ if (inet->rcv_saddr != saddr)
+ continue;
+ if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
+ continue;
+ if (sock_flag(sk, SOCK_DEAD))
+ continue;
+
+ sock_hold(sk);
+ spin_unlock_bh(lock);
+
+ local_bh_disable();
+ bh_lock_sock(sk);
+ sk->sk_err = ETIMEDOUT;
+ sk->sk_error_report(sk);
+
+ tcp_done(sk);
+ bh_unlock_sock(sk);
+ local_bh_enable();
+ sock_put(sk);
+
+ goto restart;
+ }
+ spin_unlock_bh(lock);
+ }
+}
+
#ifdef CONFIG_PROC_FS
/* Proc filesystem TCP sock list dumping. */
@@ -2455,4 +2498,3 @@ EXPORT_SYMBOL(tcp_proc_register);
EXPORT_SYMBOL(tcp_proc_unregister);
#endif
EXPORT_SYMBOL(sysctl_tcp_low_latency);
-
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 2fc4a1724eb8..a88743bc0032 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -121,6 +121,7 @@ static struct {
static bool rfkill_epo_lock_active;
+static unsigned long rfkill_no;
#ifdef CONFIG_RFKILL_LEDS
static void rfkill_led_trigger_event(struct rfkill *rfkill)
@@ -693,7 +694,7 @@ static struct device_attribute rfkill_dev_attrs[] = {
__ATTR(type, S_IRUGO, rfkill_type_show, NULL),
__ATTR(index, S_IRUGO, rfkill_idx_show, NULL),
__ATTR(persistent, S_IRUGO, rfkill_persistent_show, NULL),
- __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store),
+ __ATTR(state, S_IRUGO|S_IWUGO, rfkill_state_show, rfkill_state_store),
__ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store),
__ATTR_NULL
};
@@ -880,7 +881,6 @@ static void rfkill_sync_work(struct work_struct *work)
int __must_check rfkill_register(struct rfkill *rfkill)
{
- static unsigned long rfkill_no;
struct device *dev = &rfkill->dev;
int error;
@@ -960,8 +960,8 @@ void rfkill_unregister(struct rfkill *rfkill)
mutex_lock(&rfkill_global_mutex);
rfkill_send_events(rfkill, RFKILL_OP_DEL);
list_del_init(&rfkill->node);
+ rfkill_no--;
mutex_unlock(&rfkill_global_mutex);
-
rfkill_led_trigger_unregister(rfkill);
}
EXPORT_SYMBOL(rfkill_unregister);
diff --git a/net/socket.c b/net/socket.c
index 6d4716559047..f3cfd48191af 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -96,6 +96,10 @@
#include <net/sock.h>
#include <linux/netfilter.h>
+#ifdef CONFIG_UID_STAT
+#include <linux/uid_stat.h>
+#endif
+
static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
@@ -570,7 +574,12 @@ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
if (err)
return err;
- return sock->ops->sendmsg(iocb, sock, msg, size);
+ err = sock->ops->sendmsg(iocb, sock, msg, size);
+#ifdef CONFIG_UID_STAT
+ if (err > 0)
+ update_tcp_snd(current_uid(), err);
+#endif
+ return err;
}
int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
@@ -684,7 +693,12 @@ static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
if (err)
return err;
- return sock->ops->recvmsg(iocb, sock, msg, size, flags);
+ err = sock->ops->recvmsg(iocb, sock, msg, size, flags);
+#ifdef CONFIG_UID_STAT
+ if (err > 0)
+ update_tcp_rcv(current_uid(), err);
+#endif
+ return err;
}
int sock_recvmsg(struct socket *sock, struct msghdr *msg,
diff --git a/sound/arm/mxc-alsa-spdif.c b/sound/arm/mxc-alsa-spdif.c
index 93a34cd03e11..ae48051b49e8 100644
--- a/sound/arm/mxc-alsa-spdif.c
+++ b/sound/arm/mxc-alsa-spdif.c
@@ -257,6 +257,7 @@ struct mxc_spdif_device {
* SPDIF module register base address
*/
unsigned long __iomem *reg_base;
+ unsigned long reg_phys_base;
/*!
* spdif tx available or not
@@ -943,8 +944,9 @@ static void spdif_stop_tx(struct mxc_spdif_stream *s)
*/
static void spdif_start_tx(struct mxc_spdif_stream *s)
{
- struct snd_pcm_substream *substream;
- struct snd_pcm_runtime *runtime;
+ struct snd_pcm_substream *substream = s->stream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct mxc_spdif_device *chip = snd_pcm_substream_chip(substream);
unsigned int dma_size = 0;
unsigned int offset;
int ret = 0;
@@ -960,7 +962,7 @@ static void spdif_start_tx(struct mxc_spdif_stream *s)
(NULL, runtime->dma_area + offset, dma_size,
DMA_TO_DEVICE));
- dma_request.dst_addr = (dma_addr_t) (SPDIF_BASE_ADDR + 0x2c);
+ dma_request.dst_addr = (dma_addr_t) (chip->reg_phys_base + 0x2c);
dma_request.num_of_bytes = dma_size;
mxc_dma_config(s->dma_wchannel, &dma_request, 1,
@@ -1279,15 +1281,14 @@ static void spdif_stop_rx(struct mxc_spdif_stream *s)
*/
static void spdif_start_rx(struct mxc_spdif_stream *s)
{
- struct snd_pcm_substream *substream;
- struct snd_pcm_runtime *runtime;
+ struct snd_pcm_substream *substream = s->stream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct mxc_spdif_device *chip = snd_pcm_substream_chip(substream);
unsigned int dma_size = 0;
unsigned int offset;
int ret = 0;
mxc_dma_requestbuf_t dma_request;
- substream = s->stream;
- runtime = substream->runtime;
memset(&dma_request, 0, sizeof(mxc_dma_requestbuf_t));
if (s->active) {
@@ -1305,7 +1306,7 @@ static void spdif_start_rx(struct mxc_spdif_stream *s)
DMA_FROM_DEVICE));
dma_request.src_addr =
- (dma_addr_t) (SPDIF_BASE_ADDR + SPDIF_REG_SRL);
+ (dma_addr_t) (chip->reg_phys_base + SPDIF_REG_SRL);
dma_request.num_of_bytes = dma_size;
/* config and enable sdma for RX */
mxc_dma_config(s->dma_wchannel, &dma_request, 1,
@@ -2089,6 +2090,7 @@ static int mxc_alsa_spdif_probe(struct platform_device
chip = card->private_data;
chip->card = card;
card->dev = &pdev->dev;
+ chip->reg_phys_base = res->start;
chip->reg_base = ioremap(res->start, res->end - res->start + 1);
spdif_base_addr = (unsigned long)chip->reg_base;
plat_data = (struct mxc_spdif_platform_data *)pdev->dev.platform_data;
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 4362689dd639..dd28cad09934 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -17,6 +17,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AK4104 if SPI_MASTER
select SND_SOC_AK4535 if I2C
select SND_SOC_CS4270 if I2C
+ select SND_SOC_CS42888 if I2C
select SND_SOC_PCM3008
select SND_SOC_SPDIF
select SND_SOC_SSM2602 if I2C
@@ -90,6 +91,9 @@ config SND_SOC_CS4270_VD33_ERRATA
bool
depends on SND_SOC_CS4270
+config SND_SOC_CS42888
+ tristate
+
config SND_SOC_L3
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8add6333d7c5..8fd4da08392c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -5,6 +5,7 @@ snd-soc-ak4104-objs := ak4104.o
snd-soc-ak4535-objs := ak4535.o
snd-soc-ak5702-objs := ak5702.o
snd-soc-cs4270-objs := cs4270.o
+snd-soc-cs42888-objs := cs42888.o
snd-soc-l3-objs := l3.o
snd-soc-pcm3008-objs := pcm3008.o
snd-soc-spdif-objs := spdif_transciever.o
@@ -50,6 +51,7 @@ obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK5702) += snd-soc-ak5702.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
+obj-$(CONFIG_SND_SOC_CS42888) += snd-soc-cs42888.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
diff --git a/sound/soc/codecs/mxs-adc-codec.c b/sound/soc/codecs/mxs-adc-codec.c
index 246dab352342..f8f10619731a 100644
--- a/sound/soc/codecs/mxs-adc-codec.c
+++ b/sound/soc/codecs/mxs-adc-codec.c
@@ -48,6 +48,8 @@
#define BF(value, field) (((value) << BP_##field) & BM_##field)
#endif
+#define BM_RTC_PERSISTENT0_RELEASE_GND BF(0x2, RTC_PERSISTENT0_SPARE_ANALOG)
+
#define REGS_RTC_BASE (IO_ADDRESS(RTC_PHYS_ADDR))
struct mxs_codec_priv {
@@ -252,6 +254,47 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol,
return 0;
}
+static int pga_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Prepare powering up HP and SPEAKER output */
+ __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
+ __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND,
+ REGS_RTC_BASE + HW_RTC_PERSISTENT0_SET);
+ msleep(100);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND,
+ REGS_RTC_BASE + HW_RTC_PERSISTENT0_CLR);
+ break;
+ }
+ return 0;
+}
+
+static int adc_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND,
+ REGS_RTC_BASE + HW_RTC_PERSISTENT0_SET);
+ msleep(100);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND,
+ REGS_RTC_BASE + HW_RTC_PERSISTENT0_CLR);
+ break;
+ }
+ return 0;
+}
+
static const char *mxs_codec_adc_input_sel[] =
{ "Mic", "Line In 1", "Head Phone", "Line In 2" };
@@ -282,8 +325,6 @@ static const struct snd_kcontrol_new mxs_snd_controls[] = {
SOC_DOUBLE_R("DAC Playback Switch",
DAC_VOLUME_H, DAC_VOLUME_L, 8, 0x01, 1),
SOC_DOUBLE("HP Playback Volume", DAC_HPVOL_L, 8, 0, 0x7F, 1),
- SOC_SINGLE("HP Playback Switch", DAC_HPVOL_H, 8, 0x1, 1),
- SOC_SINGLE("Speaker Playback Switch", DAC_SPEAKERCTRL_H, 8, 0x1, 1),
/* Capture Volume */
SOC_DOUBLE_R("ADC Capture Volume",
@@ -310,10 +351,10 @@ SOC_DAPM_ENUM("Route", mxs_codec_enum[2]);
static const struct snd_soc_dapm_widget mxs_codec_widgets[] = {
- SND_SOC_DAPM_ADC("Left ADC", "Left Capture", DAC_PWRDN_L, 8, 1),
- SND_SOC_DAPM_ADC("Right ADC", "Right Capture", DAC_PWRDN_H, 0, 1),
+ SND_SOC_DAPM_ADC_E("ADC", "Capture", DAC_PWRDN_L, 8, 1, adc_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC", "Playback", DAC_PWRDN_L, 12, 1),
SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
&mxs_left_adc_controls),
@@ -321,7 +362,10 @@ static const struct snd_soc_dapm_widget mxs_codec_widgets[] = {
&mxs_right_adc_controls),
SND_SOC_DAPM_MUX("HP Mux", SND_SOC_NOPM, 0, 0,
&mxs_hp_controls),
-
+ SND_SOC_DAPM_PGA_E("HP AMP", DAC_PWRDN_L, 0, 1, NULL, 0, pga_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA("SPEAKER AMP", DAC_PWRDN_H, 8, 1, NULL, 0),
SND_SOC_DAPM_INPUT("LINE1L"),
SND_SOC_DAPM_INPUT("LINE1R"),
SND_SOC_DAPM_INPUT("LINE2L"),
@@ -348,20 +392,23 @@ static const struct snd_soc_dapm_route intercon[] = {
{"Right ADC Mux", "Head Phone", "HPR"},
/* ADC */
- {"Left ADC", NULL, "Left ADC Mux"},
- {"Right ADC", NULL, "Right ADC Mux"},
+ {"ADC", NULL, "Left ADC Mux"},
+ {"ADC", NULL, "Right ADC Mux"},
/* HP Mux */
{"HP Mux", "DAC Out", "DAC"},
{"HP Mux", "Line In 1", "LINE1L"},
{"HP Mux", "Line In 1", "LINE1R"},
+ /* HP amp */
+ {"HP AMP", NULL, "HP Mux"},
/* HP output */
- {"HPR", NULL, "HP MUX"},
- {"HPL", NULL, "HP MUX"},
+ {"HPR", NULL, "HP AMP"},
+ {"HPL", NULL, "HP AMP"},
/* Speaker amp */
- {"SPEAKER", NULL, "DAC"},
+ {"SPEAKER AMP", NULL, "DAC"},
+ {"SPEAKER", NULL, "SPEAKER AMP"},
};
static int mxs_codec_add_widgets(struct snd_soc_codec *codec)
@@ -488,29 +535,84 @@ static int mxs_codec_hw_params(struct snd_pcm_substream *substream,
static int mxs_codec_dig_mute(struct snd_soc_dai *dai, int mute)
{
+ int l, r;
+ int ll, rr;
+ u32 reg, reg1, reg2;
u32 dac_mask = BM_AUDIOOUT_DACVOLUME_MUTE_LEFT |
BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT;
- u32 reg1 = 0;
- u32 reg = 0;
if (mute) {
- reg1 = __raw_readl(REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL);
- reg = reg1 | BF_AUDIOOUT_HPVOL_VOL_LEFT(0x7f) | \
- BF_AUDIOOUT_HPVOL_VOL_RIGHT(0x7f);
- __raw_writel(reg, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL);
+ reg = __raw_readl(REGS_AUDIOOUT_BASE + \
+ HW_AUDIOOUT_DACVOLUME);
+
+ reg1 = reg & ~BM_AUDIOOUT_DACVOLUME_VOLUME_LEFT;
+ reg1 = reg1 & ~BM_AUDIOOUT_DACVOLUME_VOLUME_RIGHT;
+
+ l = (reg & BM_AUDIOOUT_DACVOLUME_VOLUME_LEFT) >>
+ BP_AUDIOOUT_DACVOLUME_VOLUME_LEFT;
+ r = (reg & BM_AUDIOOUT_DACVOLUME_VOLUME_RIGHT) >>
+ BP_AUDIOOUT_DACVOLUME_VOLUME_RIGHT;
+
+ /* fade out dac vol */
+ while ((l > DAC_VOLUME_MIN) || (r > DAC_VOLUME_MIN)) {
+ l -= 0x8;
+ r -= 0x8;
+ ll = l > DAC_VOLUME_MIN ? l : DAC_VOLUME_MIN;
+ rr = r > DAC_VOLUME_MIN ? r : DAC_VOLUME_MIN;
+ reg2 = reg1 | BF_AUDIOOUT_DACVOLUME_VOLUME_LEFT(ll)
+ | BF_AUDIOOUT_DACVOLUME_VOLUME_RIGHT(rr);
+ __raw_writel(reg2,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME);
+ msleep(1);
+ }
__raw_writel(dac_mask,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME_SET);
- __raw_writel(BM_AUDIOOUT_HPVOL_MUTE,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET);
-
- __raw_writel(reg1, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL);
- } else {
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME_SET);
+ reg = reg | dac_mask;
+ __raw_writel(reg,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME);
+ } else
__raw_writel(dac_mask,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME_CLR);
- __raw_writel(BM_AUDIOOUT_HPVOL_MUTE,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_CLR);
+
+ return 0;
+}
+
+static int mxs_codec_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ pr_debug("dapm level %d\n", level);
+ switch (level) {
+ case SND_SOC_BIAS_ON: /* full On */
+ if (codec->bias_level == SND_SOC_BIAS_ON)
+ break;
+ break;
+
+ case SND_SOC_BIAS_PREPARE: /* partial On */
+ if (codec->bias_level == SND_SOC_BIAS_PREPARE)
+ break;
+ /* Set Capless mode */
+ __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR);
+ break;
+
+ case SND_SOC_BIAS_STANDBY: /* Off, with power */
+ if (codec->bias_level == SND_SOC_BIAS_STANDBY)
+ break;
+ /* Unset Capless mode */
+ __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_SET);
+ break;
+
+ case SND_SOC_BIAS_OFF: /* Off, without power */
+ if (codec->bias_level == SND_SOC_BIAS_OFF)
+ break;
+ /* Unset Capless mode */
+ __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_SET);
+ break;
}
+ codec->bias_level = level;
return 0;
}
@@ -533,6 +635,58 @@ static void mxs_codec_dac_set_vag(void)
__raw_writel(refctrl_val, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_REFCTRL);
}
+static bool mxs_codec_dac_is_capless()
+{
+ if ((__raw_readl(REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN)
+ & BM_AUDIOOUT_PWRDN_CAPLESS) == 0)
+ return false;
+ else
+ return true;
+}
+static void mxs_codec_dac_arm_short_cm(bool bShort)
+{
+ __raw_writel(BF(3, AUDIOOUT_ANACTRL_SHORTMODE_CM),
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_CM_STS,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ if (bShort)
+ __raw_writel(BF(1, AUDIOOUT_ANACTRL_SHORTMODE_CM),
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
+}
+static void mxs_codec_dac_arm_short_lr(bool bShort)
+{
+ __raw_writel(BF(3, AUDIOOUT_ANACTRL_SHORTMODE_LR),
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_LR_STS,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ if (bShort)
+ __raw_writel(BF(1, AUDIOOUT_ANACTRL_SHORTMODE_LR),
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
+}
+static void mxs_codec_dac_set_short_trip_level(u8 u8level)
+{
+ __raw_writel(__raw_readl(REGS_AUDIOOUT_BASE +
+ HW_AUDIOOUT_ANACTRL)
+ & (~BM_AUDIOOUT_ANACTRL_SHORT_LVLADJL)
+ & (~BM_AUDIOOUT_ANACTRL_SHORT_LVLADJR)
+ | BF(u8level, AUDIOOUT_ANACTRL_SHORT_LVLADJL)
+ | BF(u8level, AUDIOOUT_ANACTRL_SHORT_LVLADJR),
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL);
+}
+static void mxs_codec_dac_arm_short(bool bLatchCM, bool bLatchLR)
+{
+ if (bLatchCM) {
+ if (mxs_codec_dac_is_capless())
+ mxs_codec_dac_arm_short_cm(true);
+ } else
+ mxs_codec_dac_arm_short_cm(false);
+
+ if (bLatchLR)
+ mxs_codec_dac_arm_short_lr(true);
+ else
+ mxs_codec_dac_arm_short_lr(false);
+
+}
static void
mxs_codec_dac_power_on(struct mxs_codec_priv *mxs_adc)
{
@@ -542,17 +696,13 @@ mxs_codec_dac_power_on(struct mxs_codec_priv *mxs_adc)
__raw_writel(BM_AUDIOOUT_ANACLKCTRL_CLKGATE,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACLKCTRL_CLR);
- /* Set capless mode */
- __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS, REGS_AUDIOOUT_BASE
- + HW_AUDIOOUT_PWRDN_CLR);
-
/* 16 bit word length */
__raw_writel(BM_AUDIOOUT_CTRL_WORD_LENGTH,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_SET);
- /* Powerup DAC */
- __raw_writel(BM_AUDIOOUT_PWRDN_DAC,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR);
+ /* Arm headphone LR short protect */
+ mxs_codec_dac_set_short_trip_level(0);
+ mxs_codec_dac_arm_short(false, true);
/* Update DAC volume over zero crossings */
__raw_writel(BM_AUDIOOUT_DACVOLUME_EN_ZCD,
@@ -566,30 +716,26 @@ mxs_codec_dac_power_on(struct mxs_codec_priv *mxs_adc)
__raw_writel(BM_AUDIOOUT_HPVOL_EN_MSTR_ZCD,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET);
- /* Prepare powering up HP output */
- __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
- __raw_writel(BF(0x2, RTC_PERSISTENT0_SPARE_ANALOG),
- REGS_RTC_BASE + HW_RTC_PERSISTENT0_SET);
- __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR);
__raw_writel(BM_AUDIOOUT_ANACTRL_HP_CLASSAB,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
- __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+
/* Mute HP output */
__raw_writel(BM_AUDIOOUT_HPVOL_MUTE,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET);
- __raw_writel(BM_AUDIOOUT_PWRDN_SPEAKER,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR);
/* Mute speaker amp */
__raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_SPEAKERCTRL_SET);
+ /* Enable the audioout */
+ __raw_writel(BM_AUDIOOUT_CTRL_RUN,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_SET);
}
static void
mxs_codec_dac_power_down(struct mxs_codec_priv *mxs_adc)
{
+ /* Disable the audioout */
+ __raw_writel(BM_AUDIOOUT_CTRL_RUN,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_CLR);
/* Disable class AB */
__raw_writel(BM_AUDIOOUT_ANACTRL_HP_CLASSAB,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
@@ -858,7 +1004,8 @@ static int mxs_codec_probe(struct platform_device *pdev)
snd_soc_free_pcms(socdev);
return ret;
}
-
+ /* Set default bias level*/
+ mxs_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
@@ -982,6 +1129,8 @@ static int __init mxs_codec_audio_probe(struct platform_device *pdev)
codec->private_data = mxs_adc;
codec->read = mxs_codec_read;
codec->write = mxs_codec_write;
+ codec->bias_level = SND_SOC_BIAS_OFF;
+ codec->set_bias_level = mxs_codec_set_bias_level;
codec->dai = &mxs_codec_dai;
codec->num_dai = 1;
codec->reg_cache_size = sizeof(mxs_audio_regs) >> 1;
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index a63b65cdc04d..9bea4d8a523d 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -200,39 +200,6 @@ static void dump_reg(struct snd_soc_codec *codec)
}
#endif
-static int dac_mux_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
- struct snd_soc_codec *codec = widget->codec;
- unsigned int reg;
-
- if (ucontrol->value.enumerated.item[0]) {
- reg = sgtl5000_read(codec, SGTL5000_CHIP_CLK_TOP_CTRL);
- reg |= SGTL5000_INT_OSC_EN;
- sgtl5000_write(codec, SGTL5000_CHIP_CLK_TOP_CTRL, reg);
-
- if (codec->bias_level != SND_SOC_BIAS_ON) {
- sgtl5000_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
- snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
- sgtl5000_set_bias_level(codec, SND_SOC_BIAS_ON);
- } else
- snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
-
- reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_CTRL);
- reg &= ~(SGTL5000_LINE_OUT_MUTE | SGTL5000_HP_MUTE);
- sgtl5000_write(codec, SGTL5000_CHIP_ANA_CTRL, reg);
- } else {
- reg = sgtl5000_read(codec, SGTL5000_CHIP_CLK_TOP_CTRL);
- reg &= ~SGTL5000_INT_OSC_EN;
- sgtl5000_write(codec, SGTL5000_CHIP_CLK_TOP_CTRL, reg);
-
- snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
- sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- }
- return 0;
-}
-
static const char *adc_mux_text[] = {
"MIC_IN", "LINE_IN"
};
@@ -250,16 +217,8 @@ SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 6, 2, dac_mux_text);
static const struct snd_kcontrol_new adc_mux =
SOC_DAPM_ENUM("ADC Mux", adc_enum);
-static const struct snd_kcontrol_new dac_mux = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "DAC Mux",
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE
- | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
- .info = snd_soc_info_enum_double,
- .get = snd_soc_dapm_get_enum_double,
- .put = dac_mux_put,
- .private_value = (unsigned long)&dac_enum,
-};
+static const struct snd_kcontrol_new dac_mux =
+SOC_DAPM_ENUM("DAC Mux", dac_enum);
static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("LINE_IN"),
@@ -649,6 +608,8 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
fs = sgtl5000->lrclk;
/* SGTL5000 rev1 has a IC bug to prevent switching to MCLK from PLL. */
if (!sgtl5000->master) {
+ sys_fs = sgtl5000->lrclk;
+ clk_ctl = SGTL5000_RATE_MODE_DIV_1 << SGTL5000_RATE_MODE_SHIFT;
if (fs * 256 == sgtl5000->sysclk)
clk_ctl |= SGTL5000_MCLK_FREQ_256FS << \
SGTL5000_MCLK_FREQ_SHIFT;
@@ -783,7 +744,7 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
avoid pops. */
reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_POWER);
if (reg & SGTL5000_VAG_POWERUP)
- delay = 400;
+ delay = 600;
reg &= ~SGTL5000_VAG_POWERUP;
reg |= SGTL5000_DAC_POWERUP;
reg |= SGTL5000_HP_POWERUP;
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 921932ab2d3a..7b3963461234 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -595,6 +595,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
/* Mono Capture mixer-mux */
{"Capture Right Mixer", "Stereo", "Capture Right Mux"},
+ {"Capture Left Mixer", "Stereo", "Capture Left Mux"},
{"Capture Left Mixer", "Analogue Mix Left", "Capture Left Mux"},
{"Capture Left Mixer", "Analogue Mix Left", "Capture Right Mux"},
{"Capture Right Mixer", "Analogue Mix Right", "Capture Left Mux"},
@@ -1265,6 +1266,13 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_ON:
/* set vmid to 50k and unmute dac */
wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0);
+
+ /* wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); */
+ /*
+ * Force the enable of the MICBIAS, otherwise the microphone will not
+ * work.
+ */
+ wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00e0);
break;
case SND_SOC_BIAS_PREPARE:
/* set vmid to 5k for quick power up */
@@ -1702,6 +1710,12 @@ static int wm8753_register(struct wm8753_priv *wm8753)
wm8753_codec = codec;
+ /* Configure bclk as mclk/4 */
+ reg = wm8753_read_reg_cache(codec, WM8753_SRATE2);
+ reg &= ~WM8753_BCLK_DIV_MASK;
+ reg |= WM8753_BCLK_DIV_4;
+ wm8753_write(codec, WM8753_SRATE2, reg);
+
for (i = 0; i < ARRAY_SIZE(wm8753_dai); i++)
wm8753_dai[i].dev = codec->dev;
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h
index 57b2ba244040..40c55ad713aa 100644
--- a/sound/soc/codecs/wm8753.h
+++ b/sound/soc/codecs/wm8753.h
@@ -99,6 +99,7 @@
#define WM8753_PCM_DIV_8 (7 << 6)
/* BCLK clock dividers */
+#define WM8753_BCLK_DIV_MASK (7 << 3)
#define WM8753_BCLK_DIV_1 (0 << 3)
#define WM8753_BCLK_DIV_2 (1 << 3)
#define WM8753_BCLK_DIV_4 (2 << 3)
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index 43b6d8e3b10c..afefe2c5585c 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -79,4 +79,14 @@ config SND_SOC_IMX_3STACK_BLUETOOTH
help
Say Y if you want to add support for Soc audio on IMX 3STACK
with the BLUETOOTH
+
+config SND_SOC_IMX_3STACK_CS42888
+ tristate "SoC Audio support for IMX - CS42888"
+ select SND_MXC_SOC_ESAI
+ select SND_SOC_CS42888
+ help
+ Say Y if you want to add support for Soc audio on IMX 3STACK
+ with the CS42888
+
+
endif
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index 284be7777de7..7cc8d1f32674 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -24,3 +24,6 @@ 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-3stack-cs42888-objs := imx-3stack-cs42888.o
+obj-$(CONFIG_SND_SOC_IMX_3STACK_CS42888) += snd-soc-imx-3stack-cs42888.o
+
diff --git a/sound/soc/imx/imx-3stack-ak4647.c b/sound/soc/imx/imx-3stack-ak4647.c
index 6d6a98fd02e0..56c7a498e5b1 100644
--- a/sound/soc/imx/imx-3stack-ak4647.c
+++ b/sound/soc/imx/imx-3stack-ak4647.c
@@ -363,8 +363,6 @@ static int __init imx_3stack_ak4647_probe(struct platform_device *pdev)
imx_3stack_dai.cpu_dai = ak4647_cpu_dai;
- /* Configure audio port 3 */
- gpio_activate_audio_ports();
imx_3stack_init_dam(dev_data->src_port, dev_data->ext_port);
ret = request_irq(dev_data->intr_id_hp, imx_headphone_detect_handler, 0,
@@ -388,7 +386,6 @@ err:
static int __devexit imx_3stack_ak4647_remove(struct platform_device *pdev)
{
struct mxc_audio_platform_data *dev_data = pdev->dev.platform_data;
- gpio_inactivate_audio_ports();
free_irq(dev_data->intr_id_hp, NULL);
driver_remove_file(pdev->dev.driver, &driver_attr_headphone);
return 0;
diff --git a/sound/soc/imx/imx-3stack-ak5702.c b/sound/soc/imx/imx-3stack-ak5702.c
index 7603c0f0ae19..734399434aa9 100644
--- a/sound/soc/imx/imx-3stack-ak5702.c
+++ b/sound/soc/imx/imx-3stack-ak5702.c
@@ -1,7 +1,7 @@
/*
* imx-3stack-ak5702.c -- SoC audio for imx_3stack
*
- * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -171,13 +171,11 @@ static int __devinit imx_3stack_ak5702_probe(struct platform_device *pdev)
setup->i2c_address = 0x13;
imx_3stack_snd_devdata.codec_data = setup;
- gpio_activate_esai_ports();
return 0;
}
static int imx_3stack_ak5702_remove(struct platform_device *pdev)
{
- gpio_deactivate_esai_ports();
return 0;
}
diff --git a/sound/soc/imx/imx-3stack-wm8580.c b/sound/soc/imx/imx-3stack-wm8580.c
index 631571ddb5ef..f3f9f85ca0f0 100644
--- a/sound/soc/imx/imx-3stack-wm8580.c
+++ b/sound/soc/imx/imx-3stack-wm8580.c
@@ -1,7 +1,7 @@
/*
* imx-3stack-wm8580.c -- SoC 5.1 audio for imx_3stack
*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -69,9 +69,6 @@ struct imx_3stack_pcm_state {
int lr_clk_active;
};
-extern void gpio_activate_esai_ports(void);
-extern void gpio_deactivate_esai_ports(void);
-
static struct imx_3stack_pcm_state clk_state;
static int imx_3stack_startup(struct snd_pcm_substream *substream)
@@ -374,20 +371,17 @@ static int __devinit imx_3stack_wm8580_probe(struct platform_device *pdev)
struct wm8580_setup_data *setup;
imx_3stack_dai.cpu_dai = &imx_esai_dai[2];
+ imx_3stack_dai.cpu_dai->dev = &pdev->dev;
setup = kzalloc(sizeof(struct wm8580_setup_data), GFP_KERNEL);
setup->spi = 1;
imx_3stack_snd_devdata.codec_data = setup;
- /* Configure audio port 3 */
- gpio_activate_esai_ports();
-
return 0;
}
static int __devexit imx_3stack_wm8580_remove(struct platform_device *pdev)
{
- gpio_deactivate_esai_ports();
return 0;
}
diff --git a/sound/soc/imx/imx-ccwmx51-wm8753.c b/sound/soc/imx/imx-ccwmx51-wm8753.c
index a12285fb1a8d..e92df8914b1c 100644
--- a/sound/soc/imx/imx-ccwmx51-wm8753.c
+++ b/sound/soc/imx/imx-ccwmx51-wm8753.c
@@ -54,14 +54,47 @@ static int imx_ccwmx51_audio_hw_params(struct snd_pcm_substream *substream,
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;
+ unsigned int rate = params_rate(params);
struct imx_ccwmx51_priv *priv = &card_priv;
struct imx_ssi *ssi_mode = (struct imx_ssi *)cpu_dai->private_data;
int ret = 0;
+ unsigned int pll_out = 0;
unsigned int channels = params_channels(params);
u32 dai_format;
- snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, priv->sysclk, 0);
+ switch (rate) {
+ case 8000:
+ pll_out = 12288000;
+ break;
+ case 11025:
+ pll_out = 11289600;
+ break;
+ case 16000:
+ pll_out = 12288000;
+ break;
+ case 22050:
+ pll_out = 11289600;
+ break;
+ case 32000:
+ pll_out = 12288000;
+ break;
+ case 44100:
+ pll_out = 11289600;
+ break;
+ case 48000:
+ pll_out = 12288000;
+ break;
+ case 88200:
+ pll_out = 11289600;
+ break;
+ case 96000:
+ pll_out = 12288000;
+ break;
+ default:
+ pr_info("Rate not supported.\n");
+ return -EINVAL;;
+ }
#if WM8753_SSI_MASTER
dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
@@ -94,6 +127,9 @@ static int imx_ccwmx51_audio_hw_params(struct snd_pcm_substream *substream,
/* set the SSI system clock as input (unused) */
snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, SND_SOC_CLOCK_IN);
+ priv->sysclk = pll_out;
+ snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, priv->sysclk, 0);
+ snd_soc_dai_set_pll(codec_dai, WM8753_MCLK, 13000000, pll_out);
return 0;
}
diff --git a/sound/soc/imx/imx-esai.c b/sound/soc/imx/imx-esai.c
index 71dd62cff509..0c6b234f29ec 100644
--- a/sound/soc/imx/imx-esai.c
+++ b/sound/soc/imx/imx-esai.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -35,292 +35,9 @@
#include "imx-esai.h"
#include "imx-pcm.h"
-/*#define IMX_ESAI_DUMP 1*/
-
-#ifdef IMX_ESAI_DUMP
-#define ESAI_DUMP() \
- do {pr_info("dump @ %s\n", __func__); \
- pr_info("ecr %x\n", __raw_readl(ESAI_ECR)); \
- pr_info("esr %x\n", __raw_readl(ESAI_ESR)); \
- pr_info("tfcr %x\n", __raw_readl(ESAI_TFCR)); \
- pr_info("tfsr %x\n", __raw_readl(ESAI_TFSR)); \
- pr_info("rfcr %x\n", __raw_readl(ESAI_RFCR)); \
- pr_info("rfsr %x\n", __raw_readl(ESAI_RFSR)); \
- pr_info("tsr %x\n", __raw_readl(ESAI_TSR)); \
- pr_info("saisr %x\n", __raw_readl(ESAI_SAISR)); \
- pr_info("saicr %x\n", __raw_readl(ESAI_SAICR)); \
- pr_info("tcr %x\n", __raw_readl(ESAI_TCR)); \
- pr_info("tccr %x\n", __raw_readl(ESAI_TCCR)); \
- pr_info("rcr %x\n", __raw_readl(ESAI_RCR)); \
- pr_info("rccr %x\n", __raw_readl(ESAI_RCCR)); \
- pr_info("tsma %x\n", __raw_readl(ESAI_TSMA)); \
- pr_info("tsmb %x\n", __raw_readl(ESAI_TSMB)); \
- pr_info("rsma %x\n", __raw_readl(ESAI_RSMA)); \
- pr_info("rsmb %x\n", __raw_readl(ESAI_RSMB)); \
- pr_info("prrc %x\n", __raw_readl(ESAI_PRRC)); \
- pr_info("pcrc %x\n", __raw_readl(ESAI_PCRC)); } while (0);
-#else
-#define ESAI_DUMP()
-#endif
-
-#define ESAI_IO_BASE_ADDR IO_ADDRESS(ESAI_BASE_ADDR)
-
-#define ESAI_ETDR (ESAI_IO_BASE_ADDR + 0x00)
-#define ESAI_ERDR (ESAI_IO_BASE_ADDR + 0x04)
-#define ESAI_ECR (ESAI_IO_BASE_ADDR + 0x08)
-#define ESAI_ESR (ESAI_IO_BASE_ADDR + 0x0C)
-#define ESAI_TFCR (ESAI_IO_BASE_ADDR + 0x10)
-#define ESAI_TFSR (ESAI_IO_BASE_ADDR + 0x14)
-#define ESAI_RFCR (ESAI_IO_BASE_ADDR + 0x18)
-#define ESAI_RFSR (ESAI_IO_BASE_ADDR + 0x1C)
-#define ESAI_TX0 (ESAI_IO_BASE_ADDR + 0x80)
-#define ESAI_TX1 (ESAI_IO_BASE_ADDR + 0x84)
-#define ESAI_TX2 (ESAI_IO_BASE_ADDR + 0x88)
-#define ESAI_TX3 (ESAI_IO_BASE_ADDR + 0x8C)
-#define ESAI_TX4 (ESAI_IO_BASE_ADDR + 0x90)
-#define ESAI_TX5 (ESAI_IO_BASE_ADDR + 0x94)
-#define ESAI_TSR (ESAI_IO_BASE_ADDR + 0x98)
-#define ESAI_RX0 (ESAI_IO_BASE_ADDR + 0xA0)
-#define ESAI_RX1 (ESAI_IO_BASE_ADDR + 0xA4)
-#define ESAI_RX2 (ESAI_IO_BASE_ADDR + 0xA8)
-#define ESAI_RX3 (ESAI_IO_BASE_ADDR + 0xAC)
-#define ESAI_SAISR (ESAI_IO_BASE_ADDR + 0xCC)
-#define ESAI_SAICR (ESAI_IO_BASE_ADDR + 0xD0)
-#define ESAI_TCR (ESAI_IO_BASE_ADDR + 0xD4)
-#define ESAI_TCCR (ESAI_IO_BASE_ADDR + 0xD8)
-#define ESAI_RCR (ESAI_IO_BASE_ADDR + 0xDC)
-#define ESAI_RCCR (ESAI_IO_BASE_ADDR + 0xE0)
-#define ESAI_TSMA (ESAI_IO_BASE_ADDR + 0xE4)
-#define ESAI_TSMB (ESAI_IO_BASE_ADDR + 0xE8)
-#define ESAI_RSMA (ESAI_IO_BASE_ADDR + 0xEC)
-#define ESAI_RSMB (ESAI_IO_BASE_ADDR + 0xF0)
-#define ESAI_PRRC (ESAI_IO_BASE_ADDR + 0xF8)
-#define ESAI_PCRC (ESAI_IO_BASE_ADDR + 0xFC)
-
-#define ESAI_ECR_ETI (1 << 19)
-#define ESAI_ECR_ETO (1 << 18)
-#define ESAI_ECR_ERI (1 << 17)
-#define ESAI_ECR_ERO (1 << 16)
-#define ESAI_ECR_ERST (1 << 1)
-#define ESAI_ECR_ESAIEN (1 << 0)
-
-#define ESAI_ESR_TINIT (1 << 10)
-#define ESAI_ESR_RFF (1 << 9)
-#define ESAI_ESR_TFE (1 << 8)
-#define ESAI_ESR_TLS (1 << 7)
-#define ESAI_ESR_TDE (1 << 6)
-#define ESAI_ESR_TED (1 << 5)
-#define ESAI_ESR_TD (1 << 4)
-#define ESAI_ESR_RLS (1 << 3)
-#define ESAI_ESR_RDE (1 << 2)
-#define ESAI_ESR_RED (1 << 1)
-#define ESAI_ESR_RD (1 << 0)
-
-#define ESAI_TFCR_TIEN (1 << 19)
-#define ESAI_TFCR_TE5 (1 << 7)
-#define ESAI_TFCR_TE4 (1 << 6)
-#define ESAI_TFCR_TE3 (1 << 5)
-#define ESAI_TFCR_TE2 (1 << 4)
-#define ESAI_TFCR_TE1 (1 << 3)
-#define ESAI_TFCR_TE0 (1 << 2)
-#define ESAI_TFCR_TFR (1 << 1)
-#define ESAI_TFCR_TFEN (1 << 0)
-#define ESAI_TFCR_TE(x) ((0x3f >> (6 - ((x + 1) >> 1))) << 2)
-#define ESAI_TFCR_TE_MASK 0xfff03
-#define ESAI_TFCR_TFWM(x) ((x - 1) << 8)
-#define ESAI_TFCR_TWA_MASK 0xf8ffff
-
-#define ESAI_RFCR_REXT (1 << 19)
-#define ESAI_RFCR_RE3 (1 << 5)
-#define ESAI_RFCR_RE2 (1 << 4)
-#define ESAI_RFCR_RE1 (1 << 3)
-#define ESAI_RFCR_RE0 (1 << 2)
-#define ESAI_RFCR_RFR (1 << 1)
-#define ESAI_RFCR_RFEN (1 << 0)
-#define ESAI_RFCR_RE(x) ((0xf >> (4 - ((x + 1) >> 1))) << 3)
-#define ESAI_RFCR_RE_MASK 0xfffc3
-#define ESAI_RFCR_RFWM(x) ((x-1) << 8)
-#define ESAI_RFCR_RWA_MASK 0xf8ffff
-
-#define ESAI_WORD_LEN_32 (0x00 << 16)
-#define ESAI_WORD_LEN_28 (0x01 << 16)
-#define ESAI_WORD_LEN_24 (0x02 << 16)
-#define ESAI_WORD_LEN_20 (0x03 << 16)
-#define ESAI_WORD_LEN_16 (0x04 << 16)
-#define ESAI_WORD_LEN_12 (0x05 << 16)
-#define ESAI_WORD_LEN_8 (0x06 << 16)
-#define ESAI_WORD_LEN_4 (0x07 << 16)
-
-#define ESAI_SAISR_TODFE (1 << 17)
-#define ESAI_SAISR_TEDE (1 << 16)
-#define ESAI_SAISR_TDE (1 << 15)
-#define ESAI_SAISR_TUE (1 << 14)
-#define ESAI_SAISR_TFS (1 << 13)
-#define ESAI_SAISR_RODF (1 << 10)
-#define ESAI_SAISR_REDF (1 << 9)
-#define ESAI_SAISR_RDF (1 << 8)
-#define ESAI_SAISR_ROE (1 << 7)
-#define ESAI_SAISR_RFS (1 << 6)
-#define ESAI_SAISR_IF2 (1 << 2)
-#define ESAI_SAISR_IF1 (1 << 1)
-#define ESAI_SAISR_IF0 (1 << 0)
-
-#define ESAI_SAICR_ALC (1 << 8)
-#define ESAI_SAICR_TEBE (1 << 7)
-#define ESAI_SAICR_SYNC (1 << 6)
-#define ESAI_SAICR_OF2 (1 << 2)
-#define ESAI_SAICR_OF1 (1 << 1)
-#define ESAI_SAICR_OF0 (1 << 0)
-
-#define ESAI_TCR_TLIE (1 << 23)
-#define ESAI_TCR_TIE (1 << 22)
-#define ESAI_TCR_TEDIE (1 << 21)
-#define ESAI_TCR_TEIE (1 << 20)
-#define ESAI_TCR_TPR (1 << 19)
-#define ESAI_TCR_PADC (1 << 17)
-#define ESAI_TCR_TFSR (1 << 16)
-#define ESAI_TCR_TFSL (1 << 15)
-#define ESAI_TCR_TWA (1 << 7)
-#define ESAI_TCR_TSHFD_MSB (0 << 6)
-#define ESAI_TCR_TSHFD_LSB (1 << 6)
-#define ESAI_TCR_TE5 (1 << 5)
-#define ESAI_TCR_TE4 (1 << 4)
-#define ESAI_TCR_TE3 (1 << 3)
-#define ESAI_TCR_TE2 (1 << 2)
-#define ESAI_TCR_TE1 (1 << 1)
-#define ESAI_TCR_TE0 (1 << 0)
-#define ESAI_TCR_TE(x) (0x3f >> (6 - ((x + 1) >> 1)))
-
-#define ESAI_TCR_TSWS_MASK 0xff83ff
-#define ESAI_TCR_TSWS_STL8_WDL8 (0x00 << 10)
-#define ESAI_TCR_TSWS_STL12_WDL8 (0x04 << 10)
-#define ESAI_TCR_TSWS_STL12_WDL12 (0x01 << 10)
-#define ESAI_TCR_TSWS_STL16_WDL8 (0x08 << 10)
-#define ESAI_TCR_TSWS_STL16_WDL12 (0x05 << 10)
-#define ESAI_TCR_TSWS_STL16_WDL16 (0x02 << 10)
-#define ESAI_TCR_TSWS_STL20_WDL8 (0x0c << 10)
-#define ESAI_TCR_TSWS_STL20_WDL12 (0x09 << 10)
-#define ESAI_TCR_TSWS_STL20_WDL16 (0x06 << 10)
-#define ESAI_TCR_TSWS_STL20_WDL20 (0x03 << 10)
-#define ESAI_TCR_TSWS_STL24_WDL8 (0x10 << 10)
-#define ESAI_TCR_TSWS_STL24_WDL12 (0x0d << 10)
-#define ESAI_TCR_TSWS_STL24_WDL16 (0x0a << 10)
-#define ESAI_TCR_TSWS_STL24_WDL20 (0x07 << 10)
-#define ESAI_TCR_TSWS_STL24_WDL24 (0x1e << 10)
-#define ESAI_TCR_TSWS_STL32_WDL8 (0x18 << 10)
-#define ESAI_TCR_TSWS_STL32_WDL12 (0x15 << 10)
-#define ESAI_TCR_TSWS_STL32_WDL16 (0x12 << 10)
-#define ESAI_TCR_TSWS_STL32_WDL20 (0x0f << 10)
-#define ESAI_TCR_TSWS_STL32_WDL24 (0x1f << 10)
-
-#define ESAI_TCR_TMOD_MASK 0xfffcff
-#define ESAI_TCR_TMOD_NORMAL (0x00 << 8)
-#define ESAI_TCR_TMOD_ONDEMAND (0x01 << 8)
-#define ESAI_TCR_TMOD_NETWORK (0x01 << 8)
-#define ESAI_TCR_TMOD_RESERVED (0x02 << 8)
-#define ESAI_TCR_TMOD_AC97 (0x03 << 8)
-
-#define ESAI_TCCR_THCKD (1 << 23)
-#define ESAI_TCCR_TFSD (1 << 22)
-#define ESAI_TCCR_TCKD (1 << 21)
-#define ESAI_TCCR_THCKP (1 << 20)
-#define ESAI_TCCR_TFSP (1 << 19)
-#define ESAI_TCCR_TCKP (1 << 18)
-
-#define ESAI_TCCR_TPSR_MASK 0xfffeff
-#define ESAI_TCCR_TPSR_BYPASS (1 << 8)
-#define ESAI_TCCR_TPSR_DIV8 (0 << 8)
-
-#define ESAI_TCCR_TFP_MASK 0xfc3fff
-#define ESAI_TCCR_TFP(x) ((x & 0xf) << 14)
-
-#define ESAI_TCCR_TDC_MASK 0xffc1ff
-#define ESAI_TCCR_TDC(x) (((x) & 0x1f) << 9)
-
-#define ESAI_TCCR_TPM_MASK 0xffff00
-#define ESAI_TCCR_TPM(x) (x & 0xff)
-
-#define ESAI_RCR_RLIE (1 << 23)
-#define ESAI_RCR_RIE (1 << 22)
-#define ESAI_RCR_REDIE (1 << 21)
-#define ESAI_RCR_REIE (1 << 20)
-#define ESAI_RCR_RPR (1 << 19)
-#define ESAI_RCR_RFSR (1 << 16)
-#define ESAI_RCR_RFSL (1 << 15)
-#define ESAI_RCR_RWA (1 << 7)
-#define ESAI_RCR_RSHFD_MSB (0 << 6)
-#define ESAI_RCR_RSHFD_LSB (1 << 6)
-#define ESAI_RCR_RE3 (1 << 3)
-#define ESAI_RCR_RE2 (1 << 2)
-#define ESAI_RCR_RE1 (1 << 1)
-#define ESAI_RCR_RE0 (1 << 0)
-#define ESAI_RCR_RE(x) ((0xf >> (4 - ((x + 1) >> 1))) << 1)
-
-#define ESAI_RCR_RSWS_MASK 0xff83ff
-#define ESAI_RCR_RSWS_STL8_WDL8 (0x00 << 10)
-#define ESAI_RCR_RSWS_STL12_WDL8 (0x04 << 10)
-#define ESAI_RCR_RSWS_STL12_WDL12 (0x01 << 10)
-#define ESAI_RCR_RSWS_STL16_WDL8 (0x08 << 10)
-#define ESAI_RCR_RSWS_STL16_WDL12 (0x05 << 10)
-#define ESAI_RCR_RSWS_STL16_WDL16 (0x02 << 10)
-#define ESAI_RCR_RSWS_STL20_WDL8 (0x0c << 10)
-#define ESAI_RCR_RSWS_STL20_WDL12 (0x09 << 10)
-#define ESAI_RCR_RSWS_STL20_WDL16 (0x06 << 10)
-#define ESAI_RCR_RSWS_STL20_WDL20 (0x03 << 10)
-#define ESAI_RCR_RSWS_STL24_WDL8 (0x10 << 10)
-#define ESAI_RCR_RSWS_STL24_WDL12 (0x0d << 10)
-#define ESAI_RCR_RSWS_STL24_WDL16 (0x0a << 10)
-#define ESAI_RCR_RSWS_STL24_WDL20 (0x07 << 10)
-#define ESAI_RCR_RSWS_STL24_WDL24 (0x1e << 10)
-#define ESAI_RCR_RSWS_STL32_WDL8 (0x18 << 10)
-#define ESAI_RCR_RSWS_STL32_WDL12 (0x15 << 10)
-#define ESAI_RCR_RSWS_STL32_WDL16 (0x12 << 10)
-#define ESAI_RCR_RSWS_STL32_WDL20 (0x0f << 10)
-#define ESAI_RCR_RSWS_STL32_WDL24 (0x1f << 10)
-
-#define ESAI_RCR_RMOD_MASK 0xfffcff
-#define ESAI_RCR_RMOD_NORMAL (0x00 << 8)
-#define ESAI_RCR_RMOD_ONDEMAND (0x01 << 8)
-#define ESAI_RCR_RMOD_NETWORK (0x01 << 8)
-#define ESAI_RCR_RMOD_RESERVED (0x02 << 8)
-#define ESAI_RCR_RMOD_AC97 (0x03 << 8)
-
-#define ESAI_RCCR_RHCKD (1 << 23)
-#define ESAI_RCCR_RFSD (1 << 22)
-#define ESAI_RCCR_RCKD (1 << 21)
-#define ESAI_RCCR_RHCKP (1 << 20)
-#define ESAI_RCCR_RFSP (1 << 19)
-#define ESAI_RCCR_RCKP (1 << 18)
-
-#define ESAI_RCCR_RPSR_MASK 0xfffeff
-#define ESAI_RCCR_RPSR_BYPASS (1 << 8)
-#define ESAI_RCCR_RPSR_DIV8 (0 << 8)
-
-#define ESAI_RCCR_RFP_MASK 0xfc3fff
-#define ESAI_RCCR_RFP(x) ((x & 0xf) << 14)
-
-#define ESAI_RCCR_RDC_MASK 0xffc1ff
-#define ESAI_RCCR_RDC(x) (((x) & 0x1f) << 9)
-
-#define ESAI_RCCR_RPM_MASK 0xffff00
-#define ESAI_RCCR_RPM(x) (x & 0xff)
-
-#define ESAI_GPIO_ESAI 0xfff
-
-/* ESAI clock source */
-#define ESAI_CLK_FSYS 0
-#define ESAI_CLK_EXTAL 1
-
-/* ESAI clock divider */
-#define ESAI_TX_DIV_PSR 0
-#define ESAI_TX_DIV_PM 1
-#define ESAI_TX_DIV_FP 2
-#define ESAI_RX_DIV_PSR 3
-#define ESAI_RX_DIV_PM 4
-#define ESAI_RX_DIV_FP 5
-
static int imx_esai_txrx_state;
static struct imx_esai imx_esai_priv[3];
+static void __iomem *esai_ioaddr;
static int imx_esai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
@@ -341,10 +58,8 @@ static int imx_esai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
~(ESAI_RCCR_RHCKD | ESAI_RCCR_RCKD |
ESAI_RCCR_RFSD);
} else {
- if (cpu_dai->id & IMX_DAI_ESAI_TX)
tccr |=
ESAI_TCCR_THCKD | ESAI_TCCR_TCKD | ESAI_TCCR_TFSD;
- if (cpu_dai->id & IMX_DAI_ESAI_RX)
rccr |=
ESAI_RCCR_RHCKD | ESAI_RCCR_RCKD | ESAI_RCCR_RFSD;
if (clk_id == ESAI_CLK_FSYS) {
@@ -353,14 +68,10 @@ static int imx_esai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
if (cpu_dai->id & IMX_DAI_ESAI_RX)
ecr &= ~(ESAI_ECR_ERI | ESAI_ECR_ERO);
} else if (clk_id == ESAI_CLK_EXTAL) {
- if (cpu_dai->id & IMX_DAI_ESAI_TX) {
ecr |= ESAI_ECR_ETI;
ecr &= ~ESAI_ECR_ETO;
- }
- if (cpu_dai->id & IMX_DAI_ESAI_RX) {
ecr |= ESAI_ECR_ERI;
ecr &= ~ESAI_ECR_ERO;
- }
}
}
@@ -386,7 +97,10 @@ static int imx_esai_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
switch (div_id) {
case ESAI_TX_DIV_PSR:
tccr &= ESAI_TCCR_TPSR_MASK;
- tccr |= div;
+ if (div)
+ tccr |= ESAI_TCCR_TPSR_BYPASS;
+ else
+ tccr &= ~ESAI_TCCR_TPSR_DIV8;
break;
case ESAI_TX_DIV_PM:
tccr &= ESAI_TCCR_TPM_MASK;
@@ -398,7 +112,10 @@ static int imx_esai_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
break;
case ESAI_RX_DIV_PSR:
rccr &= ESAI_RCCR_RPSR_MASK;
- rccr |= div;
+ if (div)
+ rccr |= ESAI_RCCR_RPSR_BYPASS;
+ else
+ rccr &= ~ESAI_RCCR_RPSR_DIV8;
break;
case ESAI_RX_DIV_PM:
rccr &= ESAI_RCCR_RPM_MASK;
@@ -691,7 +408,7 @@ static int imx_esai_hw_rx_params(struct snd_pcm_substream *substream,
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
rfcr |= ESAI_WORD_LEN_16;
- rcr |= ESAI_RCR_RSHFD_MSB | ESAI_RCR_RSWS_STL16_WDL16;
+ rcr |= ESAI_RCR_RSHFD_MSB | ESAI_RCR_RSWS_STL32_WDL16;
break;
}
@@ -729,6 +446,7 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
u32 reg, tfcr = 0, rfcr = 0;
+ u32 temp;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
tfcr = __raw_readl(ESAI_TFCR);
@@ -748,6 +466,9 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd,
reg |= ESAI_TCR_TE(substream->runtime->channels);
__raw_writel(reg, ESAI_TCR);
} else {
+ temp = __raw_readl(ESAI_TCR);
+ temp &= ~ESAI_TCR_TPR;
+ __raw_writel(temp, ESAI_TCR);
rfcr |= ESAI_RFCR_RFEN;
__raw_writel(rfcr, ESAI_RFCR);
reg &= ~ESAI_RCR_RPR;
@@ -783,7 +504,6 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd,
default:
return -EINVAL;
}
-
ESAI_DUMP();
return 0;
}
@@ -932,14 +652,53 @@ struct snd_soc_dai imx_esai_dai[] = {
EXPORT_SYMBOL_GPL(imx_esai_dai);
+static int imx_esai_dev_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct mxc_esai_platform_data *plat_data = pdev->dev.platform_data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ esai_ioaddr = ioremap(res->start, res->end - res->start + 1);
+
+ if (plat_data->activate_esai_ports)
+ plat_data->activate_esai_ports();
+
+ snd_soc_register_dais(imx_esai_dai, ARRAY_SIZE(imx_esai_dai));
+ return 0;
+}
+
+static int __devexit imx_esai_dev_remove(struct platform_device *pdev)
+{
+
+ struct mxc_esai_platform_data *plat_data = pdev->dev.platform_data;
+ iounmap(esai_ioaddr);
+ if (plat_data->deactivate_esai_ports)
+ plat_data->deactivate_esai_ports();
+
+ snd_soc_unregister_dais(imx_esai_dai, ARRAY_SIZE(imx_esai_dai));
+ return 0;
+}
+
+
+static struct platform_driver imx_esai_driver = {
+ .probe = imx_esai_dev_probe,
+ .remove = __devexit_p(imx_esai_dev_remove),
+ .driver = {
+ .name = "mxc_esai",
+ },
+};
+
static int __init imx_esai_init(void)
{
- return snd_soc_register_dais(imx_esai_dai, ARRAY_SIZE(imx_esai_dai));
+ return platform_driver_register(&imx_esai_driver);
}
static void __exit imx_esai_exit(void)
{
- snd_soc_unregister_dais(imx_esai_dai, ARRAY_SIZE(imx_esai_dai));
+ platform_driver_unregister(&imx_esai_driver);
}
module_init(imx_esai_init);
diff --git a/sound/soc/imx/imx-esai.h b/sound/soc/imx/imx-esai.h
index 58ad601c119f..6e2cce0eff4a 100644
--- a/sound/soc/imx/imx-esai.h
+++ b/sound/soc/imx/imx-esai.h
@@ -1,7 +1,7 @@
/*
* imx-esai.h -- ESAI driver header file for Freescale IMX
*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -16,6 +16,290 @@
#ifndef _MXC_ESAI_H
#define _MXC_ESAI_H
+/*#define IMX_ESAI_DUMP 1*/
+
+#ifdef IMX_ESAI_DUMP
+#define ESAI_DUMP() \
+ do {pr_info("dump @ %s\n", __func__); \
+ pr_info("ecr %x\n", __raw_readl(ESAI_ECR)); \
+ pr_info("esr %x\n", __raw_readl(ESAI_ESR)); \
+ pr_info("tfcr %x\n", __raw_readl(ESAI_TFCR)); \
+ pr_info("tfsr %x\n", __raw_readl(ESAI_TFSR)); \
+ pr_info("rfcr %x\n", __raw_readl(ESAI_RFCR)); \
+ pr_info("rfsr %x\n", __raw_readl(ESAI_RFSR)); \
+ pr_info("tsr %x\n", __raw_readl(ESAI_TSR)); \
+ pr_info("saisr %x\n", __raw_readl(ESAI_SAISR)); \
+ pr_info("saicr %x\n", __raw_readl(ESAI_SAICR)); \
+ pr_info("tcr %x\n", __raw_readl(ESAI_TCR)); \
+ pr_info("tccr %x\n", __raw_readl(ESAI_TCCR)); \
+ pr_info("rcr %x\n", __raw_readl(ESAI_RCR)); \
+ pr_info("rccr %x\n", __raw_readl(ESAI_RCCR)); \
+ pr_info("tsma %x\n", __raw_readl(ESAI_TSMA)); \
+ pr_info("tsmb %x\n", __raw_readl(ESAI_TSMB)); \
+ pr_info("rsma %x\n", __raw_readl(ESAI_RSMA)); \
+ pr_info("rsmb %x\n", __raw_readl(ESAI_RSMB)); \
+ pr_info("prrc %x\n", __raw_readl(ESAI_PRRC)); \
+ pr_info("pcrc %x\n", __raw_readl(ESAI_PCRC)); } while (0);
+#else
+#define ESAI_DUMP()
+#endif
+
+#define ESAI_IO_BASE_ADDR (esai_ioaddr)
+
+#define ESAI_ETDR (ESAI_IO_BASE_ADDR + 0x00)
+#define ESAI_ERDR (ESAI_IO_BASE_ADDR + 0x04)
+#define ESAI_ECR (ESAI_IO_BASE_ADDR + 0x08)
+#define ESAI_ESR (ESAI_IO_BASE_ADDR + 0x0C)
+#define ESAI_TFCR (ESAI_IO_BASE_ADDR + 0x10)
+#define ESAI_TFSR (ESAI_IO_BASE_ADDR + 0x14)
+#define ESAI_RFCR (ESAI_IO_BASE_ADDR + 0x18)
+#define ESAI_RFSR (ESAI_IO_BASE_ADDR + 0x1C)
+#define ESAI_TX0 (ESAI_IO_BASE_ADDR + 0x80)
+#define ESAI_TX1 (ESAI_IO_BASE_ADDR + 0x84)
+#define ESAI_TX2 (ESAI_IO_BASE_ADDR + 0x88)
+#define ESAI_TX3 (ESAI_IO_BASE_ADDR + 0x8C)
+#define ESAI_TX4 (ESAI_IO_BASE_ADDR + 0x90)
+#define ESAI_TX5 (ESAI_IO_BASE_ADDR + 0x94)
+#define ESAI_TSR (ESAI_IO_BASE_ADDR + 0x98)
+#define ESAI_RX0 (ESAI_IO_BASE_ADDR + 0xA0)
+#define ESAI_RX1 (ESAI_IO_BASE_ADDR + 0xA4)
+#define ESAI_RX2 (ESAI_IO_BASE_ADDR + 0xA8)
+#define ESAI_RX3 (ESAI_IO_BASE_ADDR + 0xAC)
+#define ESAI_SAISR (ESAI_IO_BASE_ADDR + 0xCC)
+#define ESAI_SAICR (ESAI_IO_BASE_ADDR + 0xD0)
+#define ESAI_TCR (ESAI_IO_BASE_ADDR + 0xD4)
+#define ESAI_TCCR (ESAI_IO_BASE_ADDR + 0xD8)
+#define ESAI_RCR (ESAI_IO_BASE_ADDR + 0xDC)
+#define ESAI_RCCR (ESAI_IO_BASE_ADDR + 0xE0)
+#define ESAI_TSMA (ESAI_IO_BASE_ADDR + 0xE4)
+#define ESAI_TSMB (ESAI_IO_BASE_ADDR + 0xE8)
+#define ESAI_RSMA (ESAI_IO_BASE_ADDR + 0xEC)
+#define ESAI_RSMB (ESAI_IO_BASE_ADDR + 0xF0)
+#define ESAI_PRRC (ESAI_IO_BASE_ADDR + 0xF8)
+#define ESAI_PCRC (ESAI_IO_BASE_ADDR + 0xFC)
+
+#define ESAI_ECR_ETI (1 << 19)
+#define ESAI_ECR_ETO (1 << 18)
+#define ESAI_ECR_ERI (1 << 17)
+#define ESAI_ECR_ERO (1 << 16)
+#define ESAI_ECR_ERST (1 << 1)
+#define ESAI_ECR_ESAIEN (1 << 0)
+
+#define ESAI_ESR_TINIT (1 << 10)
+#define ESAI_ESR_RFF (1 << 9)
+#define ESAI_ESR_TFE (1 << 8)
+#define ESAI_ESR_TLS (1 << 7)
+#define ESAI_ESR_TDE (1 << 6)
+#define ESAI_ESR_TED (1 << 5)
+#define ESAI_ESR_TD (1 << 4)
+#define ESAI_ESR_RLS (1 << 3)
+#define ESAI_ESR_RDE (1 << 2)
+#define ESAI_ESR_RED (1 << 1)
+#define ESAI_ESR_RD (1 << 0)
+
+#define ESAI_TFCR_TIEN (1 << 19)
+#define ESAI_TFCR_TE5 (1 << 7)
+#define ESAI_TFCR_TE4 (1 << 6)
+#define ESAI_TFCR_TE3 (1 << 5)
+#define ESAI_TFCR_TE2 (1 << 4)
+#define ESAI_TFCR_TE1 (1 << 3)
+#define ESAI_TFCR_TE0 (1 << 2)
+#define ESAI_TFCR_TFR (1 << 1)
+#define ESAI_TFCR_TFEN (1 << 0)
+#define ESAI_TFCR_TE(x) ((0x3f >> (6 - ((x + 1) >> 1))) << 2)
+#define ESAI_TFCR_TE_MASK 0xfff03
+#define ESAI_TFCR_TFWM(x) ((x - 1) << 8)
+#define ESAI_TFCR_TWA_MASK 0xf8ffff
+
+#define ESAI_RFCR_REXT (1 << 19)
+#define ESAI_RFCR_RE3 (1 << 5)
+#define ESAI_RFCR_RE2 (1 << 4)
+#define ESAI_RFCR_RE1 (1 << 3)
+#define ESAI_RFCR_RE0 (1 << 2)
+#define ESAI_RFCR_RFR (1 << 1)
+#define ESAI_RFCR_RFEN (1 << 0)
+#define ESAI_RFCR_RE(x) ((0xf >> (4 - ((x + 1) >> 1))) << 2)
+#define ESAI_RFCR_RE_MASK 0xfffc3
+#define ESAI_RFCR_RFWM(x) ((x-1) << 8)
+#define ESAI_RFCR_RWA_MASK 0xf8ffff
+
+#define ESAI_WORD_LEN_32 (0x00 << 16)
+#define ESAI_WORD_LEN_28 (0x01 << 16)
+#define ESAI_WORD_LEN_24 (0x02 << 16)
+#define ESAI_WORD_LEN_20 (0x03 << 16)
+#define ESAI_WORD_LEN_16 (0x04 << 16)
+#define ESAI_WORD_LEN_12 (0x05 << 16)
+#define ESAI_WORD_LEN_8 (0x06 << 16)
+#define ESAI_WORD_LEN_4 (0x07 << 16)
+
+#define ESAI_SAISR_TODFE (1 << 17)
+#define ESAI_SAISR_TEDE (1 << 16)
+#define ESAI_SAISR_TDE (1 << 15)
+#define ESAI_SAISR_TUE (1 << 14)
+#define ESAI_SAISR_TFS (1 << 13)
+#define ESAI_SAISR_RODF (1 << 10)
+#define ESAI_SAISR_REDF (1 << 9)
+#define ESAI_SAISR_RDF (1 << 8)
+#define ESAI_SAISR_ROE (1 << 7)
+#define ESAI_SAISR_RFS (1 << 6)
+#define ESAI_SAISR_IF2 (1 << 2)
+#define ESAI_SAISR_IF1 (1 << 1)
+#define ESAI_SAISR_IF0 (1 << 0)
+
+#define ESAI_SAICR_ALC (1 << 8)
+#define ESAI_SAICR_TEBE (1 << 7)
+#define ESAI_SAICR_SYNC (1 << 6)
+#define ESAI_SAICR_OF2 (1 << 2)
+#define ESAI_SAICR_OF1 (1 << 1)
+#define ESAI_SAICR_OF0 (1 << 0)
+
+#define ESAI_TCR_TLIE (1 << 23)
+#define ESAI_TCR_TIE (1 << 22)
+#define ESAI_TCR_TEDIE (1 << 21)
+#define ESAI_TCR_TEIE (1 << 20)
+#define ESAI_TCR_TPR (1 << 19)
+#define ESAI_TCR_PADC (1 << 17)
+#define ESAI_TCR_TFSR (1 << 16)
+#define ESAI_TCR_TFSL (1 << 15)
+#define ESAI_TCR_TWA (1 << 7)
+#define ESAI_TCR_TSHFD_MSB (0 << 6)
+#define ESAI_TCR_TSHFD_LSB (1 << 6)
+#define ESAI_TCR_TE5 (1 << 5)
+#define ESAI_TCR_TE4 (1 << 4)
+#define ESAI_TCR_TE3 (1 << 3)
+#define ESAI_TCR_TE2 (1 << 2)
+#define ESAI_TCR_TE1 (1 << 1)
+#define ESAI_TCR_TE0 (1 << 0)
+#define ESAI_TCR_TE(x) (0x3f >> (6 - ((x + 1) >> 1)))
+
+#define ESAI_TCR_TSWS_MASK 0xff83ff
+#define ESAI_TCR_TSWS_STL8_WDL8 (0x00 << 10)
+#define ESAI_TCR_TSWS_STL12_WDL8 (0x04 << 10)
+#define ESAI_TCR_TSWS_STL12_WDL12 (0x01 << 10)
+#define ESAI_TCR_TSWS_STL16_WDL8 (0x08 << 10)
+#define ESAI_TCR_TSWS_STL16_WDL12 (0x05 << 10)
+#define ESAI_TCR_TSWS_STL16_WDL16 (0x02 << 10)
+#define ESAI_TCR_TSWS_STL20_WDL8 (0x0c << 10)
+#define ESAI_TCR_TSWS_STL20_WDL12 (0x09 << 10)
+#define ESAI_TCR_TSWS_STL20_WDL16 (0x06 << 10)
+#define ESAI_TCR_TSWS_STL20_WDL20 (0x03 << 10)
+#define ESAI_TCR_TSWS_STL24_WDL8 (0x10 << 10)
+#define ESAI_TCR_TSWS_STL24_WDL12 (0x0d << 10)
+#define ESAI_TCR_TSWS_STL24_WDL16 (0x0a << 10)
+#define ESAI_TCR_TSWS_STL24_WDL20 (0x07 << 10)
+#define ESAI_TCR_TSWS_STL24_WDL24 (0x1e << 10)
+#define ESAI_TCR_TSWS_STL32_WDL8 (0x18 << 10)
+#define ESAI_TCR_TSWS_STL32_WDL12 (0x15 << 10)
+#define ESAI_TCR_TSWS_STL32_WDL16 (0x12 << 10)
+#define ESAI_TCR_TSWS_STL32_WDL20 (0x0f << 10)
+#define ESAI_TCR_TSWS_STL32_WDL24 (0x1f << 10)
+
+#define ESAI_TCR_TMOD_MASK 0xfffcff
+#define ESAI_TCR_TMOD_NORMAL (0x00 << 8)
+#define ESAI_TCR_TMOD_ONDEMAND (0x01 << 8)
+#define ESAI_TCR_TMOD_NETWORK (0x01 << 8)
+#define ESAI_TCR_TMOD_RESERVED (0x02 << 8)
+#define ESAI_TCR_TMOD_AC97 (0x03 << 8)
+
+#define ESAI_TCCR_THCKD (1 << 23)
+#define ESAI_TCCR_TFSD (1 << 22)
+#define ESAI_TCCR_TCKD (1 << 21)
+#define ESAI_TCCR_THCKP (1 << 20)
+#define ESAI_TCCR_TFSP (1 << 19)
+#define ESAI_TCCR_TCKP (1 << 18)
+
+#define ESAI_TCCR_TPSR_MASK 0xfffeff
+#define ESAI_TCCR_TPSR_BYPASS (1 << 8)
+#define ESAI_TCCR_TPSR_DIV8 (0 << 8)
+
+#define ESAI_TCCR_TFP_MASK 0xfc3fff
+#define ESAI_TCCR_TFP(x) ((x & 0xf) << 14)
+
+#define ESAI_TCCR_TDC_MASK 0xffc1ff
+#define ESAI_TCCR_TDC(x) (((x) & 0x1f) << 9)
+
+#define ESAI_TCCR_TPM_MASK 0xffff00
+#define ESAI_TCCR_TPM(x) (x & 0xff)
+
+#define ESAI_RCR_RLIE (1 << 23)
+#define ESAI_RCR_RIE (1 << 22)
+#define ESAI_RCR_REDIE (1 << 21)
+#define ESAI_RCR_REIE (1 << 20)
+#define ESAI_RCR_RPR (1 << 19)
+#define ESAI_RCR_RFSR (1 << 16)
+#define ESAI_RCR_RFSL (1 << 15)
+#define ESAI_RCR_RWA (1 << 7)
+#define ESAI_RCR_RSHFD_MSB (0 << 6)
+#define ESAI_RCR_RSHFD_LSB (1 << 6)
+#define ESAI_RCR_RE3 (1 << 3)
+#define ESAI_RCR_RE2 (1 << 2)
+#define ESAI_RCR_RE1 (1 << 1)
+#define ESAI_RCR_RE0 (1 << 0)
+#define ESAI_RCR_RE(x) (0xf >> (4 - ((x + 1) >> 1)))
+
+#define ESAI_RCR_RSWS_MASK 0xff83ff
+#define ESAI_RCR_RSWS_STL8_WDL8 (0x00 << 10)
+#define ESAI_RCR_RSWS_STL12_WDL8 (0x04 << 10)
+#define ESAI_RCR_RSWS_STL12_WDL12 (0x01 << 10)
+#define ESAI_RCR_RSWS_STL16_WDL8 (0x08 << 10)
+#define ESAI_RCR_RSWS_STL16_WDL12 (0x05 << 10)
+#define ESAI_RCR_RSWS_STL16_WDL16 (0x02 << 10)
+#define ESAI_RCR_RSWS_STL20_WDL8 (0x0c << 10)
+#define ESAI_RCR_RSWS_STL20_WDL12 (0x09 << 10)
+#define ESAI_RCR_RSWS_STL20_WDL16 (0x06 << 10)
+#define ESAI_RCR_RSWS_STL20_WDL20 (0x03 << 10)
+#define ESAI_RCR_RSWS_STL24_WDL8 (0x10 << 10)
+#define ESAI_RCR_RSWS_STL24_WDL12 (0x0d << 10)
+#define ESAI_RCR_RSWS_STL24_WDL16 (0x0a << 10)
+#define ESAI_RCR_RSWS_STL24_WDL20 (0x07 << 10)
+#define ESAI_RCR_RSWS_STL24_WDL24 (0x1e << 10)
+#define ESAI_RCR_RSWS_STL32_WDL8 (0x18 << 10)
+#define ESAI_RCR_RSWS_STL32_WDL12 (0x15 << 10)
+#define ESAI_RCR_RSWS_STL32_WDL16 (0x12 << 10)
+#define ESAI_RCR_RSWS_STL32_WDL20 (0x0f << 10)
+#define ESAI_RCR_RSWS_STL32_WDL24 (0x1f << 10)
+
+#define ESAI_RCR_RMOD_MASK 0xfffcff
+#define ESAI_RCR_RMOD_NORMAL (0x00 << 8)
+#define ESAI_RCR_RMOD_ONDEMAND (0x01 << 8)
+#define ESAI_RCR_RMOD_NETWORK (0x01 << 8)
+#define ESAI_RCR_RMOD_RESERVED (0x02 << 8)
+#define ESAI_RCR_RMOD_AC97 (0x03 << 8)
+
+#define ESAI_RCCR_RHCKD (1 << 23)
+#define ESAI_RCCR_RFSD (1 << 22)
+#define ESAI_RCCR_RCKD (1 << 21)
+#define ESAI_RCCR_RHCKP (1 << 20)
+#define ESAI_RCCR_RFSP (1 << 19)
+#define ESAI_RCCR_RCKP (1 << 18)
+
+#define ESAI_RCCR_RPSR_MASK 0xfffeff
+#define ESAI_RCCR_RPSR_BYPASS (1 << 8)
+#define ESAI_RCCR_RPSR_DIV8 (0 << 8)
+
+#define ESAI_RCCR_RFP_MASK 0xfc3fff
+#define ESAI_RCCR_RFP(x) ((x & 0xf) << 14)
+
+#define ESAI_RCCR_RDC_MASK 0xffc1ff
+#define ESAI_RCCR_RDC(x) (((x) & 0x1f) << 9)
+
+#define ESAI_RCCR_RPM_MASK 0xffff00
+#define ESAI_RCCR_RPM(x) (x & 0xff)
+
+#define ESAI_GPIO_ESAI 0xfff
+
+/* ESAI clock source */
+#define ESAI_CLK_FSYS 0
+#define ESAI_CLK_EXTAL 1
+
+/* ESAI clock divider */
+#define ESAI_TX_DIV_PSR 0
+#define ESAI_TX_DIV_PM 1
+#define ESAI_TX_DIV_FP 2
+#define ESAI_RX_DIV_PSR 3
+#define ESAI_RX_DIV_PM 4
+#define ESAI_RX_DIV_FP 5
+
#define IMX_DAI_ESAI_TX 0x04
#define IMX_DAI_ESAI_RX 0x08
#define IMX_DAI_ESAI_TXRX (IMX_DAI_ESAI_TX | IMX_DAI_ESAI_RX)
diff --git a/sound/soc/imx/imx-pcm.c b/sound/soc/imx/imx-pcm.c
index 2487d9284ac3..3e8a90da35c2 100644
--- a/sound/soc/imx/imx-pcm.c
+++ b/sound/soc/imx/imx-pcm.c
@@ -579,6 +579,14 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
else {
buf->area = iram_alloc(size, &buf_paddr);
buf->addr = buf_paddr;
+
+ if (!buf->area) {
+ pr_warning("imx-pcm: Falling back to external ram.\n");
+ UseIram = 0;
+ buf->area =
+ dma_alloc_writecombine(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ }
}
if (!buf->area)
diff --git a/sound/soc/mxs/mxs-adc.c b/sound/soc/mxs/mxs-adc.c
index e8bb4255fff5..7069927b1ac3 100644
--- a/sound/soc/mxs/mxs-adc.c
+++ b/sound/soc/mxs/mxs-adc.c
@@ -37,6 +37,7 @@
#define MXS_ADC_RATES SNDRV_PCM_RATE_8000_192000
#define MXS_ADC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
+#define ADC_VOLUME_MIN 0x37
struct mxs_pcm_dma_params mxs_audio_in = {
.name = "mxs-audio-in",
@@ -50,6 +51,166 @@ struct mxs_pcm_dma_params mxs_audio_out = {
.irq = IRQ_DAC_DMA,
};
+static struct delayed_work work;
+static struct delayed_work adc_ramp_work;
+static struct delayed_work dac_ramp_work;
+static bool adc_ramp_done = 1;
+static bool dac_ramp_done = 1;
+
+static void mxs_adc_schedule_work(struct delayed_work *work)
+{
+ schedule_delayed_work(work, HZ / 10);
+}
+static void mxs_adc_work(struct work_struct *work)
+{
+ /* disable irq */
+ disable_irq(IRQ_HEADPHONE_SHORT);
+
+ while (true) {
+ __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR);
+ msleep(10);
+ if ((__raw_readl(REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL)
+ & BM_AUDIOOUT_ANACTRL_SHORT_LR_STS) != 0) {
+ /* rearm the short protection */
+ __raw_writel(BM_AUDIOOUT_ANACTRL_SHORTMODE_LR,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_LR_STS,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ __raw_writel(BF_AUDIOOUT_ANACTRL_SHORTMODE_LR(0x1),
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
+
+ __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_SET);
+ printk(KERN_WARNING "WARNING : Headphone LR short!\r\n");
+ } else {
+ printk(KERN_WARNING "INFO : Headphone LR no longer short!\r\n");
+ break;
+ }
+ msleep(1000);
+ }
+
+ /* power up the HEADPHONE and un-mute the HPVOL */
+ __raw_writel(BM_AUDIOOUT_HPVOL_MUTE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_CLR);
+ __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR);
+
+ /* enable irq for next short detect*/
+ enable_irq(IRQ_HEADPHONE_SHORT);
+}
+
+static void mxs_adc_schedule_ramp_work(struct delayed_work *work)
+{
+ schedule_delayed_work(work, msecs_to_jiffies(2));
+ adc_ramp_done = 0;
+}
+
+static void mxs_adc_ramp_work(struct work_struct *work)
+{
+ u32 reg = 0;
+ u32 reg1 = 0;
+ u32 reg2 = 0;
+ u32 l, r;
+ u32 ll, rr;
+ int i;
+
+ reg = __raw_readl(REGS_AUDIOIN_BASE + \
+ HW_AUDIOIN_ADCVOLUME);
+
+ reg1 = reg & ~BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT;
+ reg1 = reg1 & ~BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT;
+ /* minimize adc volume */
+ reg2 = reg1 |
+ BF_AUDIOIN_ADCVOLUME_VOLUME_LEFT(ADC_VOLUME_MIN) |
+ BF_AUDIOIN_ADCVOLUME_VOLUME_RIGHT(ADC_VOLUME_MIN);
+ __raw_writel(reg2,
+ REGS_AUDIOIN_BASE + HW_AUDIOIN_ADCVOLUME);
+ msleep(1);
+
+ l = (reg & BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT) >>
+ BP_AUDIOIN_ADCVOLUME_VOLUME_LEFT;
+ r = (reg & BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT) >>
+ BP_AUDIOIN_ADCVOLUME_VOLUME_RIGHT;
+
+ /* fade in adc vol */
+ for (i = ADC_VOLUME_MIN; (i < l) || (i < r);) {
+ i += 0x8;
+ ll = i < l ? i : l;
+ rr = i < r ? i : r;
+ reg2 = reg1 |
+ BF_AUDIOIN_ADCVOLUME_VOLUME_LEFT(ll) |
+ BF_AUDIOIN_ADCVOLUME_VOLUME_RIGHT(rr);
+ __raw_writel(reg2,
+ REGS_AUDIOIN_BASE + HW_AUDIOIN_ADCVOLUME);
+ msleep(1);
+ }
+ adc_ramp_done = 1;
+}
+
+static void mxs_dac_schedule_ramp_work(struct delayed_work *work)
+{
+ schedule_delayed_work(work, msecs_to_jiffies(2));
+ dac_ramp_done = 0;
+}
+
+static void mxs_dac_ramp_work(struct work_struct *work)
+{
+ u32 reg = 0;
+ u32 reg1 = 0;
+ u32 l, r;
+ u32 ll, rr;
+ int i;
+
+ /* unmute hp and speaker */
+ __raw_writel(BM_AUDIOOUT_HPVOL_MUTE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_CLR);
+ __raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_SPEAKERCTRL_CLR);
+
+ reg = __raw_readl(REGS_AUDIOOUT_BASE + \
+ HW_AUDIOOUT_HPVOL);
+
+ reg1 = reg & ~BM_AUDIOOUT_HPVOL_VOL_LEFT;
+ reg1 = reg1 & ~BM_AUDIOOUT_HPVOL_VOL_RIGHT;
+
+ l = (reg & BM_AUDIOOUT_HPVOL_VOL_LEFT) >>
+ BP_AUDIOOUT_HPVOL_VOL_LEFT;
+ r = (reg & BM_AUDIOOUT_HPVOL_VOL_RIGHT) >>
+ BP_AUDIOOUT_HPVOL_VOL_RIGHT;
+ /* fade in hp vol */
+ for (i = 0x7f; i > 0 ;) {
+ i -= 0x8;
+ ll = i > (int)l ? i : l;
+ rr = i > (int)r ? i : r;
+ reg = reg1 | BF_AUDIOOUT_HPVOL_VOL_LEFT(ll)
+ | BF_AUDIOOUT_HPVOL_VOL_RIGHT(rr);
+ __raw_writel(reg,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL);
+ msleep(1);
+ }
+ dac_ramp_done = 1;
+}
+
+static irqreturn_t mxs_short_irq(int irq, void *dev_id)
+{
+ __raw_writel(BM_AUDIOOUT_ANACTRL_SHORTMODE_LR,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_LR_STS,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ __raw_writel(BF_AUDIOOUT_ANACTRL_SHORTMODE_LR(0x1),
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
+
+ __raw_writel(BM_AUDIOOUT_HPVOL_MUTE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET);
+ __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_SET);
+ __raw_writel(BM_AUDIOOUT_ANACTRL_HP_CLASSAB,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
+
+ mxs_adc_schedule_work(&work);
+ return IRQ_HANDLED;
+}
static irqreturn_t mxs_err_irq(int irq, void *dev_id)
{
struct snd_pcm_substream *substream = dev_id;
@@ -104,68 +265,47 @@ static int mxs_adc_trigger(struct snd_pcm_substream *substream,
{
int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0;
int ret = 0;
- u32 reg = 0;
- u32 reg1 = 0;
- u32 l, r;
- u32 ll, rr;
- int i;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
if (playback) {
- reg = __raw_readl(REGS_AUDIOOUT_BASE + \
- HW_AUDIOOUT_HPVOL);
- reg1 = BM_AUDIOOUT_HPVOL_VOL_LEFT | \
- BM_AUDIOOUT_HPVOL_VOL_RIGHT;
- __raw_writel(reg1, REGS_AUDIOOUT_BASE + \
- HW_AUDIOOUT_HPVOL);
-
- __raw_writel(BM_AUDIOOUT_CTRL_RUN,
+ /* enable the fifo error interrupt */
+ __raw_writel(BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_SET);
- __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
-
- reg1 = reg & ~BM_AUDIOOUT_HPVOL_VOL_LEFT;
- reg1 = reg1 & ~BM_AUDIOOUT_HPVOL_VOL_RIGHT;
-
- l = (reg & BM_AUDIOOUT_HPVOL_VOL_LEFT) >>
- BP_AUDIOOUT_HPVOL_VOL_LEFT;
- r = (reg & BM_AUDIOOUT_HPVOL_VOL_RIGHT) >>
- BP_AUDIOOUT_HPVOL_VOL_RIGHT;
- for (i = 0x7f; i > 0 ; i -= 0x8) {
- ll = i > l ? i : l;
- rr = i > r ? i : r;
- /* fade in hp vol */
- reg = reg1 | BF_AUDIOOUT_HPVOL_VOL_LEFT(ll)
- | BF_AUDIOOUT_HPVOL_VOL_RIGHT(rr);
- __raw_writel(reg,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL);
- udelay(100);
- }
- __raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE,
- REGS_AUDIOIN_BASE + HW_AUDIOOUT_SPEAKERCTRL_CLR);
- }
- else
+ /* write a data to data reg to trigger the transfer */
+ __raw_writel(0x0,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DATA);
+ mxs_dac_schedule_ramp_work(&dac_ramp_work);
+ } else {
__raw_writel(BM_AUDIOIN_CTRL_RUN,
REGS_AUDIOIN_BASE + HW_AUDIOIN_CTRL_SET);
-
+ mxs_adc_schedule_ramp_work(&adc_ramp_work);
+ }
break;
case SNDRV_PCM_TRIGGER_STOP:
if (playback) {
- __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
+ if (dac_ramp_done == 0) {
+ cancel_delayed_work(&dac_ramp_work);
+ dac_ramp_done = 1;
+ }
+ __raw_writel(BM_AUDIOOUT_HPVOL_MUTE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET);
__raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_SPEAKERCTRL_SET);
-
- __raw_writel(BM_AUDIOOUT_CTRL_RUN,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_SPEAKERCTRL_SET);
+ /* disable the fifo error interrupt */
+ __raw_writel(BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_CLR);
- }
- else
+ } else {
+ if (adc_ramp_done == 0) {
+ cancel_delayed_work(&adc_ramp_work);
+ adc_ramp_done = 1;
+ }
__raw_writel(BM_AUDIOIN_CTRL_RUN,
REGS_AUDIOIN_BASE + HW_AUDIOIN_CTRL_CLR);
+ }
break;
case SNDRV_PCM_TRIGGER_RESUME:
@@ -187,8 +327,13 @@ static int mxs_adc_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0;
int irq;
+ int irq_short;
int ret;
+ INIT_DELAYED_WORK(&work, mxs_adc_work);
+ INIT_DELAYED_WORK(&adc_ramp_work, mxs_adc_ramp_work);
+ INIT_DELAYED_WORK(&dac_ramp_work, mxs_dac_ramp_work);
+
if (playback) {
irq = IRQ_DAC_ERROR;
cpu_dai->dma_data = &mxs_audio_out;
@@ -205,14 +350,21 @@ static int mxs_adc_startup(struct snd_pcm_substream *substream,
return ret;
}
+ irq_short = IRQ_HEADPHONE_SHORT;
+ ret = request_irq(irq_short, mxs_short_irq,
+ IRQF_DISABLED | IRQF_SHARED, "MXS DAC/ADC HP SHORT", substream);
+ if (ret) {
+ printk(KERN_ERR "%s: Unable to request ADC/DAC HP SHORT irq %d\n",
+ __func__, IRQ_DAC_ERROR);
+ return ret;
+ }
+
/* Enable error interrupt */
if (playback) {
__raw_writel(BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_CLR);
__raw_writel(BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_CLR);
- __raw_writel(BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_SET);
} else {
__raw_writel(BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ,
REGS_AUDIOIN_BASE + HW_AUDIOIN_CTRL_CLR);
diff --git a/sound/soc/mxs/mxs-dai.c b/sound/soc/mxs/mxs-dai.c
index a548b9948516..9ca22ecdb4b0 100644
--- a/sound/soc/mxs/mxs-dai.c
+++ b/sound/soc/mxs/mxs-dai.c
@@ -288,6 +288,7 @@ static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
default:
return -EINVAL;
}
+ break;
default:
return -EINVAL;
}
diff --git a/sound/soc/mxs/mxs-evk-adc.c b/sound/soc/mxs/mxs-evk-adc.c
index bd1ed6bf691f..16c1cb4fab96 100644
--- a/sound/soc/mxs/mxs-evk-adc.c
+++ b/sound/soc/mxs/mxs-evk-adc.c
@@ -33,12 +33,119 @@
#include "mxs-adc.h"
#include "mxs-pcm.h"
+/* mxs evk machine connections to the codec pins */
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* HPR/HPL OUT --> Headphone Jack */
+ {"Headphone Jack", NULL, "HPR"},
+ {"Headphone Jack", NULL, "HPL"},
+
+ /* SPEAKER OUT --> Ext Speaker */
+ {"Ext Spk", NULL, "SPEAKER"},
+};
+
+static int mxs_evk_jack_func;
+static int mxs_evk_spk_func;
+
+static const char *jack_function[] = { "off", "on"};
+
+static const char *spk_function[] = { "off", "on" };
+
+
+static const struct soc_enum mxs_evk_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, jack_function),
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static int mxs_evk_get_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.enumerated.item[0] = mxs_evk_jack_func;
+ return 0;
+}
+
+static int mxs_evk_set_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (mxs_evk_jack_func == ucontrol->value.enumerated.item[0])
+ return 0;
+
+ mxs_evk_jack_func = ucontrol->value.enumerated.item[0];
+ if (mxs_evk_jack_func)
+ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+ else
+ snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+
+ snd_soc_dapm_sync(codec);
+ return 1;
+}
+
+static int mxs_evk_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.enumerated.item[0] = mxs_evk_spk_func;
+ return 0;
+}
+
+static int mxs_evk_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (mxs_evk_spk_func == ucontrol->value.enumerated.item[0])
+ return 0;
+
+ mxs_evk_spk_func = ucontrol->value.enumerated.item[0];
+ if (mxs_evk_spk_func)
+ snd_soc_dapm_enable_pin(codec, "Ext Spk");
+ else
+ snd_soc_dapm_disable_pin(codec, "Ext Spk");
+
+ snd_soc_dapm_sync(codec);
+ return 1;
+}
+/* mxs evk card dapm widgets */
+static const struct snd_soc_dapm_widget mxs_evk_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+};
+
+static const struct snd_kcontrol_new mxs_evk_controls[] = {
+ SOC_ENUM_EXT("HP Playback Switch", mxs_evk_enum[0], mxs_evk_get_jack,
+ mxs_evk_set_jack),
+ SOC_ENUM_EXT("Speaker Playback Switch", mxs_evk_enum[1],
+ mxs_evk_get_spk, mxs_evk_set_spk),
+};
+
+static int mxs_evk_codec_init(struct snd_soc_codec *codec)
+{
+ int i, ret;
+ /* Add mxs evk specific controls */
+ snd_soc_add_controls(codec, mxs_evk_controls,
+ ARRAY_SIZE(mxs_evk_controls));
+
+ /* Add mxs evk specific widgets */
+ snd_soc_dapm_new_controls(codec, mxs_evk_dapm_widgets,
+ ARRAY_SIZE(mxs_evk_dapm_widgets));
+
+ /* Set up mxs evk specific audio path audio_map */
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ snd_soc_dapm_sync(codec);
+ /* default on */
+ mxs_evk_jack_func = 1;
+ mxs_evk_spk_func = 1;
+
+ return ret;
+}
/* mxs evk dac/adc audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link mxs_evk_codec_dai = {
.name = "MXS ADC/DAC",
.stream_name = "MXS ADC/DAC",
.cpu_dai = &mxs_adc_dai,
.codec_dai = &mxs_codec_dai,
+ .init = mxs_evk_codec_init,
};
/* mxs evk audio machine driver */
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
index a9f0358687f4..dac91e3eb8fb 100644
--- a/sound/soc/mxs/mxs-pcm.c
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -141,6 +141,7 @@ static int mxs_pcm_prepare(struct snd_pcm_substream *substream)
/* Link with previous command */
prtd->dma_desc_array[i]->cmd.cmd.bits.bytes = prtd->dma_period;
prtd->dma_desc_array[i]->cmd.cmd.bits.irq = 1;
+ prtd->dma_desc_array[i]->cmd.cmd.bits.dec_sem = 0;
prtd->dma_desc_array[i]->cmd.cmd.bits.chain = 1;
/* Set DMA direction */
if (playback)
@@ -194,6 +195,8 @@ static void mxs_pcm_stop(struct snd_pcm_substream *substream)
prtd->dma_desc_array[(desc + 1)%8]->cmd.cmd.bits.command = NO_DMA_XFER;
mxs_dma_unfreeze(prtd->dma_ch);
+
+ mxs_dma_disable(prtd->dma_ch);
}
static int mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
@@ -375,6 +378,7 @@ static int mxs_pcm_close(struct snd_pcm_substream *substream)
free_irq(prtd->params->irq, substream);
mxs_dma_get_cooked(prtd->dma_ch, &list);
/* Free DMA channel*/
+ mxs_dma_reset(prtd->dma_ch);
for (desc = 0; desc < desc_num; desc++)
mxs_dma_free_desc(prtd->dma_desc_array[desc]);
mxs_dma_release(prtd->dma_ch, mxs_pcm_dev);